By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
460,028 Members | 1,108 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 460,028 IT Pros & Developers. It's quick & easy.

Implementing my own memcpy

P: n/a
Hi,
I am trying to simulate a memcpy like this
void* mem_cpy(void* dest, void* src, int bytes)
{
dest = malloc(bytes);
}
Now if I want to copy the bytes from src to dest, how do I copy these
bytes.
I am stuck here.

Nov 15 '05 #1
Share this Question
Share on Google+
70 Replies


P: n/a
On Sat, 25 Jun 2005 07:28:30 -0700, Rajan wrote:
Hi,
I am trying to simulate a memcpy like this void* mem_cpy(void* dest, void*
src, int bytes) {
dest = malloc(bytes);
}
Now if I want to copy the bytes from src to dest, how do I copy these
bytes.
I am stuck here.


Why can't you use memcpy itself? I'll assume you have a reason that
isn't "it's a homework assignment".

Are you trying to achieve the exact same behaviour as memcpy? If so,
then don't allocate memory - memcpy requires that the memory is already
allocated. The second parameter needs to be qualified with const. Also
the type of the third parameter is size_t not int - this requires that
you include stddef.h. Even if it were declared as int it should be
unsigned.

Here is an implementation:

#include <stddef.h>

void *mem_cpy(void *dest, const void *src, size_t bytes)
{
unsigned char *srcmax = dest + bytes;

while (src < srcmax)
*(unsigned char *)dest++ = *(unsigned char *)src++;
return dest;
}

Nov 15 '05 #2

P: n/a
"Rajan" <rs*******@yahoo.com> writes:
I am trying to simulate a memcpy like this
void* mem_cpy(void* dest, void* src, int bytes)
{
dest = malloc(bytes);
}
Now if I want to copy the bytes from src to dest, how do I copy these
bytes.


This does not make sense. If you are going to copy bytes from
src to dest, then replacing dest by something else (such as the
return value of malloc()) is not going to help, because it means
that you won't be able to refer to the destination buffer any
longer.

Have you tried reading a C tutorial?
--
"I ran it on my DeathStation 9000 and demons flew out of my nose." --Kaz
Nov 15 '05 #3

P: n/a
Hi Netocrat ,
With your code fragment, I find that you are using unsigned char* , but
I may have to copy a structure.
We certainly cannot do *dest++ = *src++ ; if they are void pointers.
So how do we deal with this?

Nov 15 '05 #4

P: n/a
On Sat, 25 Jun 2005 08:16:24 -0700, Rajan wrote:
Hi Netocrat ,
With your code fragment, I find that you are using unsigned char* , but I
may have to copy a structure.
We certainly cannot do *dest++ = *src++ ; if they are void pointers. So
how do we deal with this?


I believe that there is no portable, generic way to copy a structure - you
need to write a specific routine that copies each element.

A non-portable way that will probably work would be to call the mem_cpy
function with the addresses of the destination and source structures as
the first and second parameters ie &your_struct_variable1 and
&your_struct_variable2 and with the third parameter as sizeof(struct
your_struct). I'll probably get jumped on for suggesting that though...

Regarding your comment about dest and src being void pointers:

In the code, unsigned char * is used as a cast. It doesn't change the
fact that the original pointers are void *, it just instructs the compiler
to treat them as unsigned char pointers. So you are right that *dest++ =
*src++ is invalid, because you can't dereference a pointer to void. But
typecasting them to unsigned char pointers and then dereferencing them is
guaranteed to always be valid. In this way unsigned char pointers are
unique. Interpret it like this:
1) we are given two pointers which can point to anything
2) we treat the pointers as though they each point to a single byte
(unsigned char can be interpreted as being a single byte)
3) we copy the data from the byte that the source pointer points to into
to the byte that the destination pointer points to
4) we move each pointer on to the next byte
5) we repeat steps 3 and 4 'bytes' times.

Nov 15 '05 #5

P: n/a
"Rajan" <rs*******@yahoo.com> writes:
With your code fragment, I find that you are using unsigned char* , but
I may have to copy a structure.


Any object may be copied as an array of characters.
--
"I'm not here to convince idiots not to be stupid.
They won't listen anyway."
--Dann Corbit
Nov 15 '05 #6

P: n/a
On 2005-06-25 11:45:13 -0400, Netocrat <ne******@dodo.com.au> said:
On Sat, 25 Jun 2005 08:16:24 -0700, Rajan wrote:
Hi Netocrat ,
With your code fragment, I find that you are using unsigned char* , but I
may have to copy a structure.
We certainly cannot do *dest++ = *src++ ; if they are void pointers. So
how do we deal with this?


I believe that there is no portable, generic way to copy a structure


Of course there is; in fact, there are several:

Assuming a and b are of the same complete type, any of the following
will copy the contents of a into b:

#include <stdlib.h>
#include <string.h>

/*1*/ b = a;
/*2*/ memcpy(&b, &a, sizeof b);
/*3*/ memmove(&b, &a, sizeof b);
/*4*/ const unsigned char *src = (const unsigned char*)&a;
unsigned char *dst = (unsigned char*)&b;
for(size_t i=0; i<sizeof b; ++i)
{
dst[i] = src[i];
}

--
Clark S. Cox, III
cl*******@gmail.com

Nov 15 '05 #7

P: n/a
On Sat, 25 Jun 2005 12:04:24 -0400, Clark S. Cox III wrote:
On 2005-06-25 11:45:13 -0400, Netocrat <ne******@dodo.com.au> said:
I believe that there is no portable, generic way to copy a structure


Of course there is; in fact, there are several:

Assuming a and b are of the same complete type, any of the following will
copy the contents of a into b:


I'm glad to be corrected. I know of those approaches but with all the
buzzwords - unbounded this and unspecified that - going around in this
group and without a copy of the standard - or any other authoritative
source - to refer to I'm finding it hard to know what's "conforming" - to
use another buzzword.

Nov 15 '05 #8

P: n/a
Rajan wrote:
Hi,
I am trying to simulate a memcpy like this
void* mem_cpy(void* dest, void* src, int bytes)
{
dest = malloc(bytes);
}
Now if I want to copy the bytes from src to dest, how do I copy these
bytes.
I am stuck here.

What I think you are trying to do here is duplicate some object in
memory using dynamically allocated memory to store the duplicate. If
that is the case try this:

/************************************************** ********************/
/* File Id: dupobj.c. */
/* Author: Stan Milam. */
/* Date Written: 28-Aug-1999. */
/* Description: */
/* Implement a function to duplicate an object in memory. */
/* */
/* (c) Copyright 2005 by Stan Milam. */
/* All rights reserved. */
/* */
/************************************************** ********************/

#include <errno.h>
#include <stdlib.h>
#include <string.h>

/************************************************** ********************/
/* Name: */
/* dupobj() - Duplicate an lvalue with allocated memory. */
/* */
/* Synopsis: */
/* #include "strtools.h." */
/* void *dupobj( void *obj, size_t objsize ); */
/* */
/* Description: */
/* Use the calloc() and memcpy() functions to allocate memory */
/* large enough to hold an object in memory, then use memcpy() */
/* to copy the contents of the object to the allocated memory. */
/* */
/* Arguments: */
/* void *obj */
/* size_t objsize - The size of the object in memory. */
/* */
/* Return Value: */
/* The address of the duplicated object. NULL when a memory */
/* allocation error occurs, or the *obj address is NULL. When */
/* the *obj address is NULL the global errno variable is set */
/* to EINVAL. */
/* */
/************************************************** ********************/

void *
dupobj( void *obj, size_t objsize )
{
void *rv = NULL;

if ( obj == NULL || objsize == 0 )
errno = EINVAL;
else {
if ( ( rv = calloc( 1, objsize ) ) != NULL )
memcpy( rv, obj, objsize );
}
return rv;
}

Nov 15 '05 #9

P: n/a
Rajan wrote:

Hi Netocrat ,
With your code fragment, I find that you are using unsigned char* , but
I may have to copy a structure.
We certainly cannot do *dest++ = *src++ ; if they are void pointers.
So how do we deal with this?


Always include adequate quotation from previous articles, so that
your message stands by itself. There is no reason to assume any
previous material is available to the reader.

One of my sigs reads as follows - heed it if you must use the foul
google interface. Better, get yourself a real newsreader.

"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

The point about memcpy is that it copies memory areas, measured in
bytes, with no regard for the types involved. I gather you wish
the same thing, but with automatic creation of the destination. In
this case you need a different signature, such as:

void *dupmem(void *src, size_t sz);

The void * type can point at arbitrary things, and a size_t can
specify a size on any machine. But to use void* you have to
convert to other types, thus:

void *dupmem(void *src, size_t sz)
{
unsigned char *sp = src;
unsigned char *dst;

if (dst = malloc(sz)) /* memory is available */
while (sz--) *dst++ = *sp++; /* copy away */
return dst; /* will be NULL for failure */
} /* dupmem, untested */

Note how src is typed into sp, without any casts. Similarly the
reverse typing for the return value of dupmem. The usage will be,
for p some type of pointer:

if (p = dupmem(whatever, howbig)) {
/* success, carry on */
}
else {
/* abject failure, panic */
}

--
"I conclude that there are two ways of constructing a software
design: One way is to make it so simple that there are obviously
no deficiencies and the other way is to make it so complicated
that there are no obvious deficiencies." -- C. A. R. Hoare
Nov 15 '05 #10

P: n/a
On Sun, 26 Jun 2005 01:07:00 +1000, Netocrat <ne******@dodo.com.au>
wrote:
On Sat, 25 Jun 2005 07:28:30 -0700, Rajan wrote:
(...)
#include <stddef.h>

void *mem_cpy(void *dest, const void *src, size_t bytes)
{
unsigned char *srcmax = dest + bytes;

while (src < srcmax)


I don't understand this line. You are comparing one array src to
another srcmax. Perhaps I missed something, but I do not believe that
they are looking into the same array. Did you mean to define srcmax
differently?

unsigned char* srcmax = src + bytes;

--

Best wishes,

Bob
Nov 15 '05 #11

P: n/a
In article <J7***************@newssvr11.news.prodigy.com>, Stan Milam wrote:
[...]
void *
dupobj( void *obj, size_t objsize )
Why not ``const void *obj''?
{
void *rv = NULL;

if ( obj == NULL || objsize == 0 )
errno = EINVAL;
EINVAL is not a Standard C macro (the UNIX and POSIX standards do define
it, however.) In addition, I would argue that it is the caller's
responsibility to pass valid arguments. Have you noticed that even in
Unix, library-only functions tend not to set EINVAL much, and certainly
not for invalid pointer arguments? This is because such a requirement
would needlessly slow down and bloat correctly written code, i.e. code
that always passes valid arguments. It is usually functions invoking
system calls that set errno to EINVAL because the operating system
kernel *has to* check all arguments for correctness, so as to avoid
accidental or malicious system corruption.

I will also point out that your check is incomplete anyway because
``obj'' may contain an invalid address that isn't NULL; Which, for the
purpose of setting EINVAL in Unix, is an unmapped address.
else {
if ( ( rv = calloc( 1, objsize ) ) != NULL )


This will likely execute slower than necessary, since calloc() is
conceptually a malloc() + memset(); A plain malloc() will suffice
because you immediately overwrite the memory anyway.

--
Nils R. Weller, Bremen / Germany
My real email address is ``nils<at>gnulinux<dot>nl''
.... but I'm not speaking for the Software Libre Foundation!
Nov 15 '05 #12

P: n/a
On Sat, 25 Jun 2005 13:33:47 -0400, Robert W Hand wrote:
On Sun, 26 Jun 2005 01:07:00 +1000, Netocrat <ne******@dodo.com.au> wrote:
On Sat, 25 Jun 2005 07:28:30 -0700, Rajan wrote:


(...)
#include <stddef.h>

void *mem_cpy(void *dest, const void *src, size_t bytes) {
unsigned char *srcmax = dest + bytes;

while (src < srcmax)


I don't understand this line. You are comparing one array src to another
srcmax. Perhaps I missed something, but I do not believe that they are
looking into the same array. Did you mean to define srcmax differently?

unsigned char* srcmax = src + bytes;


Yes - typo, I don't know how that snuck in there - it's obvious from the
naming that it's wrong.

Cheers.

Nov 15 '05 #13

P: n/a
In article <pa****************************@dodo.com.au>
Netocrat <ne******@dodo.com.au> wrote:
void *mem_cpy(void *dest, const void *src, size_t bytes)
{
unsigned char *srcmax = dest + bytes;

while (src < srcmax)
*(unsigned char *)dest++ = *(unsigned char *)src++;
return dest;
}


This is flawed for three reasons:

- As someone else pointed out, "srcmax" is computed from "dest"
but is used for comparison with "src".

- The "dest++" and "src++" operations are invalid because dest
and src have type "void *", and thus need to increment by
sizeof(void), as it were. (There are some non-C compilers,
such as gcc, that define sizeof(void)==1 just to make this
work anyway. There are some other non-C compilers that fail
to catch the error -- a diagnostic is required in ANSI/ISO
C, either C89 or C99 -- and treat sizeof(void) as 0, and
thus produce an infinite loop!)

- Finally, the return value (dest) would be modified from the
original input value: you would have to retract it by "bytes"
bytes first.

The easiest fix for all of these is to use auxiliary variables.
I prefer to leave the input parameters unmodified, and create
auxiliaries of type "unsigned char *":

void *like_memcpy(void *restrict dst0, const void *restrict src0,
size_t n) {
unsigned char *restrict dst = dst0;
unsigned char *restrict src = src0;

if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}

(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).

This is strictly conforming C code because it is always allowed to
examine or copy objects' representations one "C byte" (unsigned
char) at a time.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #14

P: n/a
Netocrat wrote:
On Sat, 25 Jun 2005 07:28:30 -0700, Rajan wrote:
Hi,
I am trying to simulate a memcpy like this void* mem_cpy(void* dest, void*
src, int bytes) {
dest = malloc(bytes);
}
Now if I want to copy the bytes from src to dest, how do I copy these
bytes.


Are you trying to achieve the exact same behaviour as memcpy? If so,
then don't allocate memory - memcpy requires that the memory is already
allocated. The second parameter needs to be qualified with const. Also
the type of the third parameter is size_t not int - this requires that
you include stddef.h. Even if it were declared as int it should be
unsigned.

Here is an implementation:

#include <stddef.h>

void *mem_cpy(void *dest, const void *src, size_t bytes)
{
unsigned char *srcmax = dest + bytes;

while (src < srcmax)
*(unsigned char *)dest++ = *(unsigned char *)src++;
return dest;
}


You cannot perform pointer arithmetic on void pointers, you need to
convert them to pointers to another type before you perform the
addition. memcpy should return the value of dest that is passed into the
function. So the code should be something like this:

#include <stddef.h>

void *mem_cpy( void *dest, const void *src, size_t bytes )
{
unsigned char *destPtr = dest;
unsigned char const *srcPtr = src;
unsigned char const *srcEnd = srcPtr + bytes;

while ( srcPtr < srcEnd ) {
*destPtr++ = *srcPtr++;
}
return dest;
}

Kevin.
Nov 15 '05 #15

P: n/a
On Sat, 25 Jun 2005 18:31:30 +0000, Chris Torek wrote:
In article <pa****************************@dodo.com.au> Netocrat
<ne******@dodo.com.au> wrote:
void *mem_cpy(void *dest, const void *src, size_t bytes) {
unsigned char *srcmax = dest + bytes;

while (src < srcmax)
*(unsigned char *)dest++ = *(unsigned char *)src++;
return dest;
}
} This is flawed for three reasons:

- As someone else pointed out, "srcmax" is computed from "dest"
but is used for comparison with "src".

- The "dest++" and "src++" operations are invalid because dest
and src have type "void *", and thus need to increment by
sizeof(void), as it were. (There are some non-C compilers, such as
gcc, that define sizeof(void)==1 just to make this work anyway.
There are some other non-C compilers that fail to catch the error --
a diagnostic is required in ANSI/ISO C, either C89 or C99 -- and
treat sizeof(void) as 0, and thus produce an infinite loop!)


Yes thoughts about what type the increment operator was operating on did
pass through my mind as I was writing it. When it worked (I use gcc) I
assumed that it was because the cast to unsigned char * had informed the
compiler how to properly apply pointer arithmetic - that had I left it
uncast as void * the increment operator would not have worked at all. Now
that I reconsider that assumption I can see that it's flawed because had
the cast been taken into account the result would no longer have been a
modifiable lvalue and the increment could not have been applied.

And indeed checking this shows that gcc still doesn't complain about
incrementing a void pointer.
- Finally, the return value (dest) would be modified from the
original input value: you would have to retract it by "bytes" bytes
first.
Obviously. A silly error.
The easiest fix for all of these is to use auxiliary variables. I prefer
to leave the input parameters unmodified, and create auxiliaries of type
"unsigned char *":
I've got into the habit of trying to minimise variable usage and required
calculations (sometimes orthogonal aims). That's the main reason I didn't
use variables in this case. It's not so big a deal with an optimising
compiler because little details like that all get ironed out in the wash,
but in this forum you can't make any assumptions about whether or not code
will be compiled with optimisations.

Obviously my code won't function without change. Your suggestion works.
The other option is to maintain the cast and use indexing instead of
pointer arithmetic. I don't like that option though because it requires
more calculations to index for a non-optimising compiler.

Whilst decrementing n and testing it for loop end works fine, I prefer to
test against a maximum pointer and save the cost of the decrement
operation. I think it's also more readable.
void *like_memcpy(void *restrict dst0, const void *restrict src0,
size_t n) {
unsigned char *restrict dst = dst0;
unsigned char *restrict src = src0;

if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}
(you can also write the loop as "while (n--) *dst++ = *src++" but I find
the above easier to read and think about).


I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.

Nov 15 '05 #16

P: n/a
On Sat, 25 Jun 2005 19:06:37 +0000, Kevin Bagust wrote:
Netocrat wrote: [snip code]
You cannot perform pointer arithmetic on void pointers, you need to
convert them to pointers to another type before you perform the addition.
memcpy should return the value of dest that is passed into the function.
So the code should be something like this:

#include <stddef.h>

void *mem_cpy( void *dest, const void *src, size_t bytes ) {
unsigned char *destPtr = dest;
unsigned char const *srcPtr = src;
unsigned char const *srcEnd = srcPtr + bytes;

while ( srcPtr < srcEnd ) {
*destPtr++ = *srcPtr++;
}
return dest;
}


Great - that's just how I would have rewritten it to correct the bugs -
apart from naming conventions; and I may not have thought to qualify the
pointers with const but it is appropriate and good practice.

Nov 15 '05 #17

P: n/a
>On Sat, 25 Jun 2005 18:31:30 +0000, Chris Torek wrote:
(you can also write the loop as "while (n--) *dst++ = *src++" but I find
the above easier to read and think about).

In article <pa****************************@dodo.com.au>
Netocrat <ne******@dodo.com.au> wrote:I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.


My thinking is perhaps colored by too many years of assembly coding
and instruction sets that include "decrement and branch if nonzero":

test r3
bz Laround
Lloop:
mov (r1)+,(r2)+
sobgtr r3,Lloop # cheating (but this is OK)
Laround:

and:

tst d1
bz Laround
addq #-1,d1 # dbcc/dbra uses -1 instead of 0
Lloop:
mov a1@+,a2@+
dbra d1,Lloop
# insert fixup code for 16-bit dbra instructions
...
Laround:

and so on. (The first loop is VAX assembly, and "cheating" is OK
because r1 and/or r2 should never cross from P0/P1 space to S space,
nor vice versa, so the maximum block size never exceeds 2 GB; the
second loop is 680x0 assembly and uses a special trick in the
original 68000, in which a one-instruction dbcc loop never re-fetches
the instructions over the bus, so that the loop runs about twice
as fast as any other version. You *have* to use the dbcc instructions,
no other loop construct does the trick! If you can force-fit any
repeated memory operation into a dbra, even if there is no reason
to decrement, it is worth it, on the 68000. Later CPUs had
instruction caches, making the trick obsolete, though.)

Modern CPUs have "branch on register not zero" but also may have
"branch on r1 not equal to r2". MIPS and SPARCv9 lack the latter,
so the counted loop is still better; but on SPARCv9 at least, you
really want to implement large block-copy operations using the
special cache-conserving streaming load operations, through the
floating point registers. (But that assembly code is far too
large to post off-topically to comp.lang.c :-) )
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #18

P: n/a
On Sat, 25 Jun 2005 19:58:19 +0000, Chris Torek wrote:
On Sat, 25 Jun 2005 18:31:30 +0000, Chris Torek wrote:
(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).

In article <pa****************************@dodo.com.au> Netocrat
<ne******@dodo.com.au> wrote:
I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.


My thinking is perhaps colored by too many years of assembly coding and
instruction sets that include "decrement and branch if nonzero":


Interesting where the differences lead us. I did some x86 assembly way
back - not much but enough to get the general idea. As for any other
architectures - I've used them but haven't coded their assembly.

So my thinking is based mainly on my own concepts of an 'abstract machine'
and the operations it would perform with my own idea of the abstract cost
of those operations.

In practice your thinking is likely to lead to code that is efficient on a
given set of architectures.

My approach will be more efficient on a machine in my head. :) Whether
that translates into efficiency on real machines depends on
a) the natural fit of my abstract machine to the real hardware
b) of the ability of the compiler to optimise my semantics for the real
hardware.
There is another dependency - optimising my semantics for the abstract
machine. But that's a step I deem it upon myself to take and prefer not
to rely on the compiler to provide. And that's the point where according
to my abstract concepts, the 'maximum pointer test' is cheaper than the
separate counter.

But it's only valid for my personal abstract machine. Another
programmer might have their own personal abstract machine with a
different cost weighting. And your cost calculations are valid for the
machines you know have that type of instruction.

In the end when we're talking about non-platform-specific C as on this
forum, apart from blazingly obvious inefficiencies, and representations
that can only be implemented by hardware in one particular way, things
like this are a matter of personal preference and style, would you not
agree?

[snip assembly and explanation]
Modern CPUs have "branch on register not zero" but also may have "branch
on r1 not equal to r2". MIPS and SPARCv9 lack the latter, so the
counted loop is still better; but on SPARCv9 at least, you really want
to implement large block-copy operations using the special
cache-conserving streaming load operations, through the floating point
registers. (But that assembly code is far too large to post
off-topically to comp.lang.c
:-) )


From vague memory I know x86 has the jump on zero, jump on less than etc
but I have no recollection of whether this can be combined with a
decrement in a single instruction.

We're wandering somewhat off-topic here but these are things to consider
in the context of writing non-specific code and being aware that it must
ultimately run on an implementation which will have strengths and
weaknesses. How much should you abstract those implementation-specific
strengths and weaknesses into generic ones and code for those? Is there
any validity to the concept of a generic strength or weakness for an
abstract machine?

Nov 15 '05 #19

P: n/a
Nils Weller wrote:
In article <J7***************@newssvr11.news.prodigy.com>, Stan Milam wrote:
[...]
void *
dupobj( void *obj, size_t objsize )

Why not ``const void *obj''?

{
void *rv = NULL;

if ( obj == NULL || objsize == 0 )
errno = EINVAL;

EINVAL is not a Standard C macro (the UNIX and POSIX standards do define
it, however.) In addition, I would argue that it is the caller's
responsibility to pass valid arguments. Have you noticed that even in
Unix, library-only functions tend not to set EINVAL much, and certainly
not for invalid pointer arguments? This is because such a requirement
would needlessly slow down and bloat correctly written code, i.e. code
that always passes valid arguments. It is usually functions invoking
system calls that set errno to EINVAL because the operating system
kernel *has to* check all arguments for correctness, so as to avoid
accidental or malicious system corruption.


All well and good. However, I choose to use it. I will endevor to
remove it if I post it here to mollify all the useless UBP types.

I will also point out that your check is incomplete anyway because
``obj'' may contain an invalid address that isn't NULL; Which, for the
purpose of setting EINVAL in Unix, is an unmapped address.


Well, this part I have no way of knowing so I must take it in good
faith. That does not mean I can't be defensive where I can.
else {
if ( ( rv = calloc( 1, objsize ) ) != NULL )

This will likely execute slower than necessary, since calloc() is
conceptually a malloc() + memset(); A plain malloc() will suffice
because you immediately overwrite the memory anyway.


Again, this is true, but I am comforted that the memory is clean when I
get it. Got it?

Regards,
Stan Milam.
Nov 15 '05 #20

P: n/a
Netocrat wrote:
.... snip ...
And indeed checking this shows that gcc still doesn't complain
about incrementing a void pointer.


Showing that you are using gcc incorrectly. Use -W -Wall -ansi
-pedantic. You can replace -ansi with -std=C99 if you wish and
your library can handle it.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #21

P: n/a
Netocrat wrote:
without a copy of the standard


You can get by somewhat with N869,
until you acquire a copy of the standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz

--
pete
Nov 15 '05 #22

P: n/a
Chris Torek wrote:
if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}

(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).


To me,
while (n-- != 0) {}
is very easy to read as a loop that's going to iterate
as many times as what the initial value of n is.

--
pete
Nov 15 '05 #23

P: n/a
On Sat, 25 Jun 2005 22:12:46 +0000, CBFalconer wrote:
Netocrat wrote:

... snip ...

And indeed checking this shows that gcc still doesn't complain about
incrementing a void pointer.

Showing that you are using gcc incorrectly. Use -W -Wall -ansi
-pedantic.
You can replace -ansi with -std=C99 if you wish and your library can
handle it.


The word complain was a poor choice, and if you had read it in context
you would have understood that and wouldn't have to pick nits with my
phrasing.

I said that my assumption had been that trying to increment a void
pointer "would not work at all", not that it would generate a "complaint",
and that that assumption is what caused me to falsely believe that the
cast had modified the pointer arithmetic.

So the sentence you quote was added to confirm that my assumption was
wrong: that gcc does still "work" ie compile without error given code that
increments a void pointer; not that it doesn't generate warnings.
Granted, I didn't use the options in this case but that's beside the point
I was trying to make.

I am aware of those options and usually do use them (apart from the -W
option which now that I read about it looks useful, so I'll add it in
future).

Look, I understand the importance of correctness and precision especially
in a group about a standardised programming language, but if you're going
to jump on what you see as an error in someone's phrasing - and even to go
further and make assumptions about their general use of the compiler - at
least give them the benefit of the doubt and try to see if what they're
saying can be interpreted correctly given the overall context.

Nov 15 '05 #24

P: n/a
On Sun, 26 Jun 2005 00:15:59 +0000, pete wrote:
Netocrat wrote:
without a copy of the standard


You can get by somewhat with N869,
until you acquire a copy of the standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz


How widely and fully implemented is the later standard C99 versus the
earlier C90 standard?

Nov 15 '05 #25

P: n/a
On Sun, 26 Jun 2005 04:21:17 -0500, Netocrat wrote
(in article <pa****************************@dodo.com.au>):
On Sun, 26 Jun 2005 00:15:59 +0000, pete wrote:
Netocrat wrote:
without a copy of the standard


You can get by somewhat with N869,
until you acquire a copy of the standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz


How widely and fully implemented is the later standard C99 versus the
earlier C90 standard?


Don't write anything that uses C99 extensions unless you don't
care about portability this century.

Nov 15 '05 #26

P: n/a
Netocrat wrote:
On Sat, 25 Jun 2005 22:12:46 +0000, CBFalconer wrote:

Netocrat wrote:

... snip ...
And indeed checking this shows that gcc still doesn't complain about
incrementing a void pointer.


Showing that you are using gcc incorrectly. Use -W -Wall -ansi
-pedantic.
You can replace -ansi with -std=C99 if you wish and your library can
handle it.

The word complain was a poor choice, and if you had read it in context
you would have understood that and wouldn't have to pick nits with my
phrasing.

I said that my assumption had been that trying to increment a void
pointer "would not work at all", not that it would generate a "complaint",
and that that assumption is what caused me to falsely believe that the
cast had modified the pointer arithmetic.

So the sentence you quote was added to confirm that my assumption was
wrong: that gcc does still "work" ie compile without error given code that
increments a void pointer; not that it doesn't generate warnings.
Granted, I didn't use the options in this case but that's beside the point
I was trying to make.

I am aware of those options and usually do use them (apart from the -W
option which now that I read about it looks useful, so I'll add it in
future).

Look, I understand the importance of correctness and precision especially
in a group about a standardised programming language, but if you're going
to jump on what you see as an error in someone's phrasing - and even to go
further and make assumptions about their general use of the compiler - at
least give them the benefit of the doubt and try to see if what they're
saying can be interpreted correctly given the overall context.


Yes! Amen!

Stan.
Nov 15 '05 #27

P: n/a
On Sat, 25 Jun 2005 08:40:59 -0700, Ben Pfaff wrote:
"Rajan" <rs*******@yahoo.com> writes:
With your code fragment, I find that you are using unsigned char* , but
I may have to copy a structure.


Any object may be copied as an array of characters.


But only portably using characters with an unsigned representation.

Lawrence

Nov 15 '05 #28

P: n/a
On Sun, 26 Jun 2005 05:33:17 +1000, Netocrat <ne******@dodo.com.au>
wrote:


I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.


You shouldn't. IMNSHO one should be equally comfortable with testing
against a minimum as with testing against a maximum, just as in
mathematics one should be comfortable both with proof by induction and
proof by infinite descent, and in programming with both recursion and
iteration. Not being comfortable with both directions limits you.

Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #29

P: n/a
In article <pa****************************@dodo.com.au>
Netocrat <ne******@dodo.com.au> wrote:
How widely and fully implemented is the later standard C99 versus the
earlier C90 standard?


"Not very". The situation is improving (inasmuch as C99 is an
"improvement" anyway :-) ), but slowly. A few years ago there were
no compilers that claimed even to attempt C99 support; now I think
there are two or three.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #30

P: n/a
On Sun, 26 Jun 2005 01:09:13 GMT, pete <pf*****@mindspring.com> wrote:
Chris Torek wrote:
if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}

(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).


To me,
while (n-- != 0) {}
is very easy to read as a loop that's going to iterate
as many times as what the initial value of n is.


Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}

This can be useful if one wants to work, so to speak, from the high
end to the low end of an array. In a copy routine one wants to be
able to work either way depending on overlaps. Thus if the layout
looks like this

SSSSS.....
DDDDD.....

one wants to work from the high end down whereas if it looks like

DDDDD.....
SSSSS.....

one wants to work from low end up. Thus (in a flat memory model) we
might say something like

if (src <dest) for ( ;--n >= 0 ; ) dst[n] = src[n];
else for (i=0; --n>= 0 ; i++) dst[i] = src[i];

provided that we wanted to use array indexing rather than pointers.
Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #31

P: n/a
Richard Harter wrote:
On Sun, 26 Jun 2005 01:09:13 GMT, pete <pf*****@mindspring.com> wrote:

Chris Torek wrote:

if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}

(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).


To me,
while (n-- != 0) {}
is very easy to read as a loop that's going to iterate
as many times as what the initial value of n is.

Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}


You just got yourself an infinite loop for n of unsigned integer
type -- which incidentally is the case (look upthread: size_t n).
If you insist on this form, use
for (; --n != (size_t)-1;) {}
instead. Even in situations where the cast is not necessary, I
would leave it there for clarity and as ward against
"optimisations".

[snip]

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 15 '05 #32

P: n/a
Netocrat wrote:
On Sun, 26 Jun 2005 00:15:59 +0000, pete wrote:
Netocrat wrote:
without a copy of the standard


You can get by somewhat with N869, until you acquire a copy of
the standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz


How widely and fully implemented is the later standard C99 versus
the earlier C90 standard?


The following accesses a draft that include further modifications,
but has the disadvantage of being a .pdf file rather than a .txt
file. This hampers quick and easy searches, grepping, quoting,
etc.

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf>

Meanwhile, I think I have a suitably formatted and organized
version of n869.txt mounted as:

<http://cbfalconer.home.att.net/download/n869_txt.bz2>

which means you have to have bzip2 on your system to extract it
properly, but minimizes the download time (it is about 200k).

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #33

P: n/a
Netocrat wrote:
On Sat, 25 Jun 2005 22:12:46 +0000, CBFalconer wrote:
Netocrat wrote:

... snip ...

And indeed checking this shows that gcc still doesn't complain
about incrementing a void pointer.

Showing that you are using gcc incorrectly. Use -W -Wall -ansi
-pedantic. You can replace -ansi with -std=C99 if you wish and
your library can handle it.


The word complain was a poor choice, and if you had read it in
context you would have understood that and wouldn't have to pick
nits with my phrasing.

I said that my assumption had been that trying to increment a void
pointer "would not work at all", not that it would generate a
"complaint", and that that assumption is what caused me to falsely
believe that the cast had modified the pointer arithmetic.


The point is not so much what you understand, but what other
readers of your article will understand. My post was intended to
correct the mistaken impression that gcc fails to properly diagnose
misuse of a void *.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #34

P: n/a
Netocrat wrote:

On Sun, 26 Jun 2005 00:15:59 +0000, pete wrote:
Netocrat wrote:
without a copy of the standard


You can get by somewhat with N869,
until you acquire a copy of the standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz


How widely and fully implemented is the later standard C99 versus the
earlier C90 standard?


I don't know.

http://dev.unicals.com/papers/c89-draft.html

--
pete
Nov 15 '05 #35

P: n/a
Richard Harter wrote:

On Sun, 26 Jun 2005 01:09:13 GMT, pete <pf*****@mindspring.com> wrote:
Chris Torek wrote:
if (n)
do
*dst++ = *src++;
while (--n != 0);
return dst0;
}

(you can also write the loop as "while (n--) *dst++ = *src++" but I
find the above easier to read and think about).


To me,
while (n-- != 0) {}
is very easy to read as a loop that's going to iterate
as many times as what the initial value of n is.


Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}

This can be useful if one wants to work, so to speak, from the high
end to the low end of an array.


No. Like Michael Mair said, you infinite looped.

(n-- != 0) is exactly perfect for work
from the high end to the low end of an array.

void *mem_cpy(void *s1, const void *s2, size_t n)
{
unsigned char *p1 = s1;
const unsigned char *p2 = s2;

while (n-- != 0) {
p1[n] = p2[n];
}
return s1;
}

--
pete
Nov 15 '05 #36

P: n/a
Michael Mair wrote:
Richard Harter wrote:

.... snip ...

Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}


You just got yourself an infinite loop for n of unsigned integer
type -- which incidentally is the case (look upthread: size_t n).
If you insist on this form, use
for (; --n != (size_t)-1;) {}
instead. Even in situations where the cast is not necessary, I
would leave it there for clarity and as ward against
"optimisations".


For something like that use a while loop, no need for the other for
clauses. However the for can combine initialization, and allows:

for (n = SIZE; n--; /* maybe something else */ ) {}

and is proof against unsignedness, yet n within the loop is a
direct array index. However I would normally use a while loop
anyhow.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #37

P: n/a
On Sun, 26 Jun 2005 19:36:25 +0200, Michael Mair
<Mi**********@invalid.invalid> wrote:
Richard Harter wrote: You just got yourself an infinite loop for n of unsigned integer
type -- which incidentally is the case (look upthread: size_t n).
If you insist on this form, use
for (; --n != (size_t)-1;) {}
instead. Even in situations where the cast is not necessary, I
would leave it there for clarity and as ward against
"optimisations".


My apologies. I thought it obvious that the form I mentioned required
signed integers. I didn't think it necessary to mention the caveat
but I was in error.


Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #38

P: n/a
On Sun, 26 Jun 2005 20:42:17 GMT, pete <pf*****@mindspring.com> wrote:
Richard Harter wrote:

On Sun, 26 Jun 2005 01:09:13 GMT, pete <pf*****@mindspring.com> wrote:
>Chris Torek wrote:
>
>> if (n)
>> do
>> *dst++ = *src++;
>> while (--n != 0);
>> return dst0;
>> }
>>
>> (you can also write the loop as "while (n--) *dst++ = *src++" but I
>> find the above easier to read and think about).
>
>To me,
> while (n-- != 0) {}
>is very easy to read as a loop that's going to iterate
>as many times as what the initial value of n is.
Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}

This can be useful if one wants to work, so to speak, from the high
end to the low end of an array.


No. Like Michael Mair said, you infinite looped.


Well, no, I didn't. See reply to Michael.
(n-- != 0) is exactly perfect for work
from the high end to the low end of an array.

void *mem_cpy(void *s1, const void *s2, size_t n)
{
unsigned char *p1 = s1;
const unsigned char *p2 = s2;

while (n-- != 0) {
p1[n] = p2[n];
}
return s1;
}


Point taken. That form is safe (and best) for unsigned integers.
However it is unsafe for signed integers; if for any reason n is
negative it blows up.
Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #39

P: n/a
Richard Harter wrote:

On Sun, 26 Jun 2005 20:42:17 GMT, pete <pf*****@mindspring.com> wrote:
Richard Harter wrote:

On Sun, 26 Jun 2005 01:09:13 GMT,
pete <pf*****@mindspring.com> wrote:

>Chris Torek wrote:
>
>> if (n)
>> do
>> *dst++ = *src++;
>> while (--n != 0);
>> return dst0;
>> }
>>
>> (you can also write the loop as
>> "while (n--) *dst++ = *src++" but I
>> find the above easier to read and think about).
>
>To me,
> while (n-- != 0) {}
>is very easy to read as a loop that's going to iterate
>as many times as what the initial value of n is.

Indeed. A disadvantage, though, is that n does not correspond to
array indices. An alternate formulation is

for (; --n >= 0;) {}

This can be useful if one wants to work, so to speak, from the high
end to the low end of an array.


No. Like Michael Mair said, you infinite looped.


Well, no, I didn't. See reply to Michael.


If you're thinking that n could be negative,
then it's simpler to write the code so that there
are no values of n which cause undefined behavior.

while ( n > 0) {--n;}

--
pete
Nov 15 '05 #40

P: n/a
On Sun, 26 Jun 2005 16:19:39 +0000, Richard Harter wrote:
On Sun, 26 Jun 2005 05:33:17 +1000, Netocrat <ne******@dodo.com.au> wrote:
I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.
You shouldn't.


You're dictating my personal preferences? Given a choice where all other
things are equal, you are saying that having a preference should not be
allowed?
IMNSHO one should be equally comfortable with testing
against a minimum as with testing against a maximum, just as in
mathematics one should be comfortable both with proof by induction and
proof by infinite descent, and in programming with both recursion and
iteration. Not being comfortable with both directions limits you.


Sure - I have no problems with that statement. I understand and can use
all of those concepts where appropriate - apart from proof by infinite
descent with which I am unacquainted. Where I can see no significant
benefit for using one approach over the other though, I disagree that a
preference is limiting. Often there is a link between a preference and a
level of understanding of a particular technique, but that isn't
necessarily true.

Nov 15 '05 #41

P: n/a
Netocrat wrote:
On Sat, 25 Jun 2005 22:12:46 +0000, CBFalconer wrote:
Netocrat wrote:
... snip ...

And indeed checking this shows that gcc still doesn't complain about
incrementing a void pointer.

Showing that you are using gcc incorrectly. Use -W -Wall -ansi
-pedantic.
You can replace -ansi with -std=C99 if you wish and your library can
handle it.


The word complain was a poor choice, and if you had read it in context
you would have understood that and wouldn't have to pick nits with my
phrasing.


Quit whining. Here "complain" means "produce at least one diagnostic
message" (C99 5.1.1.3). If you did not receive one for your code, you
are not compiling C; rather, you're compiling some other C-like
language (ie GNU C). C-like languages are not topical here.

Chuck is telling you or anyone listening how to invoke gcc in a
standards-compliant mode. You should listen to him.

I said that my assumption had been that trying to increment a void
pointer "would not work at all", not that it would generate a "complaint",
and that that assumption is what caused me to falsely believe that the
cast had modified the pointer arithmetic.
The difference between the two is not very meaningful. When you ignore
a diagnostic that pertains to syntax or constraint violations, you get
undefined behavior (UB). So it might work when you run it, it might
not, or it might cause earthquakes off the coast of California. What
happens when you run code containing UB is not defined by the C
standard, which is what we discuss here.
So the sentence you quote was added to confirm that my assumption was
wrong: that gcc does still "work" ie compile without error given code that
increments a void pointer; not that it doesn't generate warnings.
Granted, I didn't use the options in this case but that's beside the point
I was trying to make.

I am aware of those options and usually do use them (apart from the -W
option which now that I read about it looks useful, so I'll add it in
future).

Look, I understand the importance of correctness and precision especially
in a group about a standardised programming language, but if you're going
to jump on what you see as an error in someone's phrasing - and even to go
further and make assumptions about their general use of the compiler - at
least give them the benefit of the doubt and try to see if what they're
saying can be interpreted correctly given the overall context.


So what's your point? Either speak more precisely or grow a thicker
skin. Consider doing both if you plan on posting here regularly.
Mark F. Haigh
mf*****@sbcglobal.net

Nov 15 '05 #42

P: n/a
On Mon, 27 Jun 2005 03:44:40 -0700, Mark F. Haigh wrote:
Netocrat wrote:
On Sat, 25 Jun 2005 22:12:46 +0000, CBFalconer wrote:
> Netocrat wrote:
>>
> ... snip ...
>>
>> And indeed checking this shows that gcc still doesn't complain about
>> incrementing a void pointer.
> Showing that you are using gcc incorrectly. Use -W -Wall -ansi
> -pedantic.
> You can replace -ansi with -std=C99 if you wish and your library can
> handle it.
The word complain was a poor choice, and if you had read it in context
you would have understood that and wouldn't have to pick nits with my
phrasing.


Quit whining.

.... So what's your point? Either speak more precisely or grow a thicker
skin.
Consider doing both if you plan on posting here regularly.


I'll take your advice leave it there then.

Nov 15 '05 #43

P: n/a
On Sun, 26 Jun 2005 19:06:11 +0000, CBFalconer wrote:

<snip>
The point is not so much what you understand, but what other readers of
your article will understand. My post was intended to correct the
mistaken impression that gcc fails to properly diagnose misuse of a void
*.


Fair enough. As Mark Haigh pointed out my response was a bit of an
over-reaction. I didn't express myself well or correctly in the first
place so my later complaint against your response does seem petulant.

Nov 15 '05 #44

P: n/a
On Mon, 27 Jun 2005 06:33:44 GMT, pete <pf*****@mindspring.com> wrote:


If you're thinking that n could be negative,
then it's simpler to write the code so that there
are no values of n which cause undefined behavior.

while ( n > 0) {--n;}


This won't do; it's best to keep the flow control code out of the loop
body. However your observation is on point. The formula should work
for signed and unsigned (no separate forms for integer types), and
should produce iterate values in the range [n-1...0], and should not
execute the loop body if n<0. For ascending loops the formula

for (i=0; i<n; i++) {}

handles both signed and unsigned. For descending loops a variant of
Chris's formulation may be best, e.e.,

if (n>0) for(i=n; i-- > 0;) {}
Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #45

P: n/a
On Mon, 27 Jun 2005 19:41:07 +1000, Netocrat <ne******@dodo.com.au>
wrote:
On Sun, 26 Jun 2005 16:19:39 +0000, Richard Harter wrote:
On Sun, 26 Jun 2005 05:33:17 +1000, Netocrat <ne******@dodo.com.au> wrote:
I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.
You shouldn't.


You're dictating my personal preferences? Given a choice where all other
things are equal, you are saying that having a preference should not be
allowed?


You're inventing paranoid interpretations?

(IOW: Don't be silly.)
IMNSHO one should be equally comfortable with testing
against a minimum as with testing against a maximum, just as in
mathematics one should be comfortable both with proof by induction and
proof by infinite descent, and in programming with both recursion and
iteration. Not being comfortable with both directions limits you.


Sure - I have no problems with that statement. I understand and can use
all of those concepts where appropriate - apart from proof by infinite
descent with which I am unacquainted. Where I can see no significant
benefit for using one approach over the other though, I disagree that a
preference is limiting. Often there is a link between a preference and a
level of understanding of a particular technique, but that isn't
necessarily true.


We shall disagree, you and I. Preferences are always limiting because
they create habits that lead you to make the preferred choice without
thinking about it. If there truly is no significant difference that's
a win. However if your habit keeps you from asking the question of
which way to do it, then you lose when the choice does matter.
Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #46

P: n/a
Richard Harter wrote:

On Mon, 27 Jun 2005 06:33:44 GMT, pete <pf*****@mindspring.com> wrote:

If you're thinking that n could be negative,
then it's simpler to write the code so that there
are no values of n which cause undefined behavior.

while ( n > 0) {--n;}


This won't do; it's best to keep the flow control code out of the loop
body.


There is no flow control in the loop body.
Writing a while loop that checks the value of a variable
which was changed in the body of the loop,
is just the most natural thing.

char *str_rev(char *s)
{
char *p, *q, swap;

if (*s != '\0') {
p = s;
q = p + strlen(p + 1);
while (q > p) {
swap = *q;
*q-- = *p;
*p++ = swap;
}
}
return s;
}

--
pete
Nov 15 '05 #47

P: n/a
On Mon, 27 Jun 2005 14:25:23 GMT, pete <pf*****@mindspring.com> wrote:
Richard Harter wrote:

On Mon, 27 Jun 2005 06:33:44 GMT, pete <pf*****@mindspring.com> wrote:
>
>If you're thinking that n could be negative,
>then it's simpler to write the code so that there
>are no values of n which cause undefined behavior.
>
>while ( n > 0) {--n;}


This won't do; it's best to keep the flow control code out of the loop
body.


There is no flow control in the loop body.
Writing a while loop that checks the value of a variable
which was changed in the body of the loop,
is just the most natural thing.

Sorry, I wasn't clear. What is wanted here is a formula for which the
iteration variable is referenced within the loop body but not altered,
i.e.,

<expression generating iterate><loop body using unaltered iterate>

Of course one can write loops that change a variable within the loop;
that is the general case. In the general case the flow control code
and the loop body code are mingled together. In the special case we
can cleanly separate them if we choose to do so. AFAIK C lacks any
guaranteed way to keep the loop body from mucking with the flow
control variables; you have to use an idiom.
Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Nov 15 '05 #48

P: n/a
On Mon, 27 Jun 2005 13:54:22 +0000, Richard Harter wrote:
On Mon, 27 Jun 2005 19:41:07 +1000, Netocrat <ne******@dodo.com.au> wrote:
On Sun, 26 Jun 2005 16:19:39 +0000, Richard Harter wrote:
On Sun, 26 Jun 2005 05:33:17 +1000, Netocrat <ne******@dodo.com.au>
wrote:

I prefer the conciseness of the second, but I prefer even more testing
against a maximum pointer.

You shouldn't.


You're dictating my personal preferences? Given a choice where all other
things are equal, you are saying that having a preference should not be
allowed?


You're inventing paranoid interpretations?

(IOW: Don't be silly.)


Should I be allowed to prefer my interpretation?

Don't take that seriously - this time it was _intended_ to be silly.
IMNSHO one should be equally comfortable with testing against a minimum
as with testing against a maximum, just as in mathematics one should be
comfortable both with proof by induction and proof by infinite descent,
and in programming with both recursion and iteration. Not being
comfortable with both directions limits you.


Sure - I have no problems with that statement. I understand and can use
all of those concepts where appropriate - apart from proof by infinite
descent with which I am unacquainted. Where I can see no significant
benefit for using one approach over the other though, I disagree that a
preference is limiting. Often there is a link between a preference and a
level of understanding of a particular technique, but that isn't
necessarily true.


We shall disagree, you and I. Preferences are always limiting because
they create habits that lead you to make the preferred choice without
thinking about it. If there truly is no significant difference that's a
win. However if your habit keeps you from asking the question of which
way to do it, then you lose when the choice does matter.


Yes, no, perhaps - I suspect that we are more in agreement than
disagreement on this point anyway.

<Off-topic>
A friend once suggesed that the vast majority of arguments occur between
people who fundamentally agree but are unable to communicate with the
other person in a way that allows them to understand that they are in
agreement. I've always remembered that idea. Often I find that arguments
actually arise over subtle differences in assumptions or definitions, etc
that either don't arise during the overt argument or arise after hours of
frustrating conflict - frustrating because neither can understand the
apparent stupidity of the other in not accepting claims that are based on
assumptions or definitions which they falsely assume the other person to
share.

Anyhow this rant is better suited to a newsgroup about conflict resolution
or pop psychology so I'll leave it there.
</Off-topic>

Nov 15 '05 #49

P: n/a
On Sun, 26 Jun 2005 19:06:09 +0000, CBFalconer wrote:
Netocrat wrote:
On Sun, 26 Jun 2005 00:15:59 +0000, pete wrote:
Netocrat wrote:

without a copy of the standard

You can get by somewhat with N869, until you acquire a copy of the
standard.

http://www.open-std.org/jtc1/sc22/wg...69/n869.txt.gz


How widely and fully implemented is the later standard C99 versus the
earlier C90 standard?


The following accesses a draft that include further modifications, but has
the disadvantage of being a .pdf file rather than a .txt file. This
hampers quick and easy searches, grepping, quoting, etc.

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf>

Meanwhile, I think I have a suitably formatted and organized version of
n869.txt mounted as:

<http://cbfalconer.home.att.net/download/n869_txt.bz2>

which means you have to have bzip2 on your system to extract it properly,
but minimizes the download time (it is about 200k).


Does your text version include the modifications of the pdf version?

How is it different from the document in the link pete gave originally -
what are the modifications and when were they introduced?

Also C90 and C89 seem to be interchangeable terms - correct?

Finally I understand that C90/C89 had some modifications made prior to C99
- where are those detailed?

Nov 15 '05 #50

70 Replies

This discussion thread is closed

Replies have been disabled for this discussion.