why prefix increment is faster than postfix increment?

C

Christian Bau

"Branimir Maksimovic said:
What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior,
because using x as a double further in program
produces undefined behavior anyway.


Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);

if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.
 
B

Branimir Maksimovic

Christian said:
Branimir Maksimovic said:
What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior,
because using x as a double further in program
produces undefined behavior anyway.


Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
how about original example with:
memcpy (&x, &y, sizeof (x));
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.

Come on, this has completely different semantics then original example.
You have created valid unsigned char object at a given address
and dropped memcpy with sizeof(x). Stop playing around.

Greetings, Bane.
 
K

Keith Thompson

Branimir Maksimovic said:
Christian said:
William Hughes wrote:
Branimir Maksimovic wrote: [...]
Clearly memcpy parameter is not about number of copy operations, and
in this respect his conclusion is invalid, because if
memcpy(&x,&y,sizeof(x)-1) does not produce trap value,
implementation can use load register, store register,

Nope, you have to preseve the last byte.

What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior,
because using x as a double further in program
produces undefined behavior anyway.


Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
how about original example with:
memcpy (&x, &y, sizeof (x));
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.

Come on, this has completely different semantics then original example.
You have created valid unsigned char object at a given address
and dropped memcpy with sizeof(x). Stop playing around.

Ok, let's try again.

The code were were talking about has been buried several followups
upthread, but I think I've managed to find it:

double x, y;
memcpy (&x, &y, sizeof (x) - 1);
memcpy (&x, &y, sizeof (x));

I think each of the two memcpy() calls was intended to be considered
in isolation, not necessarily executed one after the other as implied
by the literal posted code. So let's ignore the second memcpy(), and
let's assume that sizeof(double) == 8 and CHAR_BIT==8.

The variable x is an 8-byte object. When viewed as a double, it's
uninitialized, so any attempt to access its value invokes undefined
behavior. But when viewed as an array of unsigned char, it's a
sequence of 8 elements, each of which has some value in the range
0..255 (though what those values are is, of course, indeterminate).
The same is true for y.

The statement
memcpy(&x, &y, sizeof(x)-1);
copies the first 7 bytes of y into the first 7 bytes of x. The 8th
byte of x is untouched. If the program prints the value of the 8th
byte before and after the memcpy(), it must print the same value both
times; if it doesn't, the implementation is broken.

On the other hand, if the program doesn't look at the 8th byte of x,
and the compiler can prove it doesn't matter, the memcpy() can be
legally clobber all 8 bytes of x by the as-if rule. But as far as the
abstract machine is concerned, a memcpy() of 7 bytes can only modify
those 7 bytes.
 
F

Flash Gordon

^^^^^^^^^^^^^^^^^^^^^^^^^
Christian Bau (who was not the original poster) did not conclude this.
His point was that memcpy(&x,&y,sizeof(x)) *could* be faster
than memcpy(&x,&y,sizeof(x)-1).

Clearly memcpy parameter is not about number of copy operations, and
in this respect his conclusion is invalid, because if
memcpy(&x,&y,sizeof(x)-1) does not produce trap value, ^^^^^^^^^^^^^^^^^^^^^^^^^
implementation can use load register, store register,

Nope, you have to preseve the last byte.

What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
because using x as a double further in program
produces undefined behavior anyway.

Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Looks the same to me.
how about original example with:
memcpy (&x, &y, sizeof (x));

Christian Bau was responding to a bit about memcpy (&x, &y, sizeof (x) -
1); and his post looks entirely correct to me.
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.

Come on, this has completely different semantics then original example.

This thread has been talking about both sizeof (x) and sizeof (x) - 1
for ages.
You have created valid unsigned char object at a given address
and dropped memcpy with sizeof(x). Stop playing around.

All bytes can always be read as unsigned char values, An alternative
example would have been taking a copy of the byte that memcpy is not
allowed to change and verifying afterwards that it had not changed.
 
B

Branimir Maksimovic

Keith said:
Branimir Maksimovic said:
Christian said:
Branimir Maksimovic wrote: [...]
Clearly memcpy parameter is not about number of copy operations, and
in this respect his conclusion is invalid, because if
memcpy(&x,&y,sizeof(x)-1) does not produce trap value,
implementation can use load register, store register,

Nope, you have to preseve the last byte.

What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior,
because using x as a double further in program
produces undefined behavior anyway.


Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
how about original example with:
memcpy (&x, &y, sizeof (x));
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.

Come on, this has completely different semantics then original example.
You have created valid unsigned char object at a given address
and dropped memcpy with sizeof(x). Stop playing around.

Ok, let's try again.

The code were were talking about has been buried several followups
upthread, but I think I've managed to find it:

double x, y;
memcpy (&x, &y, sizeof (x) - 1);
memcpy (&x, &y, sizeof (x));

I think each of the two memcpy() calls was intended to be considered
in isolation, not necessarily executed one after the other as implied
by the literal posted code. So let's ignore the second memcpy(), and
let's assume that sizeof(double) == 8 and CHAR_BIT==8.

The variable x is an 8-byte object. When viewed as a double, it's
uninitialized, so any attempt to access its value invokes undefined
behavior. But when viewed as an array of unsigned char, it's a
sequence of 8 elements, each of which has some value in the range
0..255 (though what those values are is, of course, indeterminate).
The same is true for y.

The statement
memcpy(&x, &y, sizeof(x)-1);
copies the first 7 bytes of y into the first 7 bytes of x. The 8th
byte of x is untouched. If the program prints the value of the 8th
byte before and after the memcpy(), it must print the same value both
times; if it doesn't, the implementation is broken.

In other words all this nonsense could be avoided by
providing just right example.

example 1:
double x,y;
unsigned char t = *(((unsigned char*)&x)+sizeof(x)-1);
memcpy(&x,&y,sizeof(x)-1);
assert(t == *(((unsigned char*)&x)+sizeof(x)-1));

example 2:
double x,y;
memcpy(&x,&y,sizeof(x));

Greetings, Bane.
 
M

Michael Wojcik

for example you could end up with a trap representation in x. say, a
signalling nan of some kind. and in any case you're not guaranteed
anything useful about the value you might get

The code in question does not use the value of x, so a trap
representation there is immaterial. And "not guaranteed anything
useful" does not constitute UB. (If it did, a great many more C
programs would have undefined behavior.)
 
S

Skarmander

Keith Thompson wrote:
The variable x is an 8-byte object. When viewed as a double, it's
uninitialized, so any attempt to access its value invokes undefined
behavior. But when viewed as an array of unsigned char, it's a
sequence of 8 elements, each of which has some value in the range
0..255 (though what those values are is, of course, indeterminate).
The same is true for y.

The statement
memcpy(&x, &y, sizeof(x)-1);
copies the first 7 bytes of y into the first 7 bytes of x. The 8th
byte of x is untouched. If the program prints the value of the 8th
byte before and after the memcpy(), it must print the same value both
times; if it doesn't, the implementation is broken.
Hmm, really?

6.7.8.10. "If an object that has automatic storage duration is not
initialized explicitly, its value is indeterminate."

3.17.2. "indeterminate value: either an unspecified value or a trap
representation"

3.17.3. "unspecified value: valid value of the relevant type where this
International Standard imposes no requirements on which value is chosen
in any instance"

But, please, I'm not trying to start a debate over what "in any
instance" could mean, and whether this in particular means a different
value could be picked every time an indeterminate value is required.
This whole thing is academic enough as it is.

Let's just say I'll agree with you, barring the existence of machines
with kaleidoscopic memory that only has a single value if it is
initialized. I'm sure there exists storage hardware with such
characteristics, but whether it is now or has ever been in use as core,
I don't know.
On the other hand, if the program doesn't look at the 8th byte of x,
and the compiler can prove it doesn't matter, the memcpy() can be
legally clobber all 8 bytes of x by the as-if rule. But as far as the
abstract machine is concerned, a memcpy() of 7 bytes can only modify
those 7 bytes.

And if a byte is never initialized, and nobody's around to read it, does
it have a value? Philosophy and C, a match made in heaven...

S.
 
P

peter koch

William Hughes skrev:
peter said:
William Hughes skrev:
[snip]
The undefined behaviour comes from reading from the uninitialized
variable y.

This is silly. Under this interpretation the code snippet

a = b;

invokes undefined behaviour. There is a limit to pedantry
even in comp.lang.c.

This might be pedantic, yes. But certainly this is according to the
standard and let's not begin to question its validity.
[An interesting question. Does reading an uninitialized variable
as a sequence of unsigned char invoke undefined behaviour]

My understanding is that this is the case. Reading uninitialized chars
might not invoke undefined behaviour, but the data was read from a
double not a char and in this case (again so far as i understand the
standard), this is undefined behaviour.
Since this was meant to show how the execution speed of an
operation defined in abstract terms can depend on the implementation,
and
alignment issues are certainly implementation dependent.
your remark is flat out wrong. You did check some of the
context before replying, didn't you?

I did. Did you read the subject line? The reply should be related to
the subject and in that context Baus example is useless.
Also the example puts an extra burden
on the compiler since it more or less requires it to know about the
semantics of memcpy. This might very well be the case, of course, but
it nevertheless makes the example "special".


Since the whole point is that the implementation may be "special"
and the compiler may be able to do intersting tricks,
(and it is anything but uncommon for a compiler to know about
the semantics of library functions) this
comment is ridiculous. You did check some of the
context before replying, didn't you?
/Peter
[snip]
The poster claimed undefined behaviour, then when challenged
claimed ignorance (and gave a stupid exuse for this
ignorance). The term "complete bullshitter" seems an accurate
description.

Reading from uninitialized variables is undefined behaviour in C++ and
almost certainly also in C.

Funny, when repeatedly challenged the poster did produce a rational
for the undefined behaviour (more exactly the claimed probability
of hardware traps). This did not involve reading from uninitialized
variables.
What the poster did or did not say does not matter. I was explaining my
own reasons for considering the program non-conforming.
-William Hughes

/Peter
 
K

Keith Thompson

Skarmander said:
Keith Thompson wrote:

Hmm, really?

Yes, really.
6.7.8.10. "If an object that has automatic storage duration is not
initialized explicitly, its value is indeterminate."

3.17.2. "indeterminate value: either an unspecified value or a trap
representation"

3.17.3. "unspecified value: valid value of the relevant type where
this International Standard imposes no requirements on which value is
chosen in any instance"

unsigned char has no trap representations. The values of the bytes
composing x and y are indeterminate and unspecified, but they're not
trap representations.
 
S

Skarmander

Keith said:
Yes, really.




unsigned char has no trap representations. The values of the bytes
composing x and y are indeterminate and unspecified, but they're not
trap representations.

Not the issue. I questioned whether or not an "unspecified value" has to
be the same actual value every time it's printed. That is, whether
it's legal for an implementation to "choose" different values for each
printf statement in the following program:

int main() {
int a;
printf("%i\n", a);
printf("%i\n", a);

return 0;
}

What's that you say? "Of course not"? Of course. I wasn't *really*
questioning it, either. Most people would consider an implementation
that didn't print the same value twice (whatever that value might be)
broken. The standard probably intends to as well. I'm just not reading
it, but that's because I'm being perverse.

The trouble with natural language is that it can't give you exact
descriptions on its lonesome; it needs a discriminating reader.

S.
 
K

Keith Thompson

Skarmander said:
Not the issue. I questioned whether or not an "unspecified value" has
to be the same actual value every time it's printed. That is, whether
it's legal for an implementation to "choose" different values for each
printf statement in the following program:

int main() {
int a;
printf("%i\n", a);
printf("%i\n", a);

return 0;
}

Well, in that particular case, a is uninitialized and *could* have a
trap representation, so it's undefined behavior.

If it's an unsigned char, I *think* the program (assuming
"#include <stdio.h>", and assuming whatever gyrations are required to
print an unsigned char even if sizeof(int)==1) is required to
print the same value twice.

The closest I can get to proving this is 6.2.4p2:

An object exists, has a constant address, and retains its
last-stored value throughout its lifetime.

but the indeterminate value that it starts with probably isn't a
"last-stored value".
 
W

William Hughes

Skarmander said:
Not the issue. I questioned whether or not an "unspecified value" has to
be the same actual value every time it's printed. That is, whether
it's legal for an implementation to "choose" different values for each
printf statement in the following program:

int main() {
int a;
printf("%i\n", a);
printf("%i\n", a);

return 0;
}

What's that you say? "Of course not"? Of course. I wasn't *really*
questioning it, either. Most people would consider an implementation
that didn't print the same value twice (whatever that value might be)
broken. The standard probably intends to as well.

I disagree. The standard does not mandate any behaviour here
and the implementation is free to take advantage of this.
(This is a good general principle. If there is no good
reason to mandate a behaviour the standard should not do so.)
As well as perverse implementations that do so just to
be a pain, there may be a good reason for this.
Consider:

int main() {

int b;
int a;
int c;
int d;

printf("%i\n", a);

b = c;

printf("%i\n", a);

return 0;
}


Now assume that for a particular implementation, b,a,c,d are in memory
in that order, ints are four bytes
and it is fastest for the implementation to
copy 8 bytes at a time. Then the compiler could note that copying the
8 bytes starting at c to the 8 bytes starting at b would have the
effect of assigning c to b and d to a. Since the second operation
is allowed, the faster operation is allowed and the compiler
could choose this.

By comp.lang.c standards this is not even a stretch.

-William Hughes
 
W

William Hughes

peter said:
William Hughes skrev:
peter said:
William Hughes skrev:
[snip]
The undefined behaviour comes from reading from the uninitialized
variable y.

This is silly. Under this interpretation the code snippet

a = b;

invokes undefined behaviour. There is a limit to pedantry
even in comp.lang.c.

This might be pedantic, yes. But certainly this is according to the
standard and let's not begin to question its validity.

The question here is not whether the code snippet invokes
undefined behaviour, but whether certain assumptions
(initialization, prototype in scope etc.) are reasonable for code
snippets. It seems to me that not making these assumptions
is unreasonable.

[An interesting question. Does reading an uninitialized variable
as a sequence of unsigned char invoke undefined behaviour]

My understanding is that this is the case. Reading uninitialized chars
might not invoke undefined behaviour, but the data was read from a
double not a char and in this case (again so far as i understand the
standard), this is undefined behaviour.

Here you are wrong. memcpy reads unsigned
char not double and any object can be safely read
as unsigned char's (unsigned char has no trap representation).
My question was whether an uninitialized double must
exist. However, according to the standard an object
must exist from the time it is declared, so it would seem that
there is no undefined behaviour here (that is assuming a prototype
for memcpy is in scope).

- William Hughes
 
B

Branimir Maksimovic

William Hughes said:
Branimir said:
William said:
Branimir Maksimovic wrote:
William Hughes wrote:
Branimir Maksimovic wrote:
Christian Bau wrote:


This is just wrong example, but if we observe this:
double x[2];y=0.;
memcpy((char*)x+1,&y,sizeof(y));
double t = *(double*)((char*)x+1); /* depends on
hardware tolerance to alignment */

I would recommend to write ((char *) x) + 1 instead of (char *)
x + 1,
so that (1) everyone knows what the expression means without
having to
look up the precedence of cast operators, and (2) everyone
knows that
what you wrote is what you meant.

memcpy(x,&y,sizeof(y));
t = *x;

It is obvious that second case will be always faster or at
least
equal then first case, even if memcpy have to copy same
number of bytes
and use ram instead or sizeof (x) ==1 .

In this case, the first assignment to t will have undefined
behavior.
There are implementations where it will crash, there are others
where it
will be set t to the same value as y, just very slowly, but it
is
undefined behavior.

Only on implementations where alignment requirement for a type
is not met.

No! It is undefined behaviour on any implementation.
The fact that it works and works the way you expect does
not make it defined behaviour

Ok, since I don't have C standard, you owe me a quote.


This is a basic thing for implementing memory allocators.
memcpy works in all cases because it is defined that char is
aligned on any address.
If that wouldn't be the case then no memory allocator can't be
written
in C or C++ without causing undefined behavior.

Assuming you did not intend the double negative, wrong.

It is not clear if you mean

- a memory allocator cannot be written in C
(i.e. a C function, say my_malloc, cannot be written)

this case.


However in either case you are incorrect

(as an extreme case consider a memory allocator that
allocates a block of 1 megabyte of memory, suitably
alligned for anything no matter how much memory is
asked for. Ruinously inefficient, but it certainly
can be done.)

I think that you don't undestand the point.


What point? Clealy my_malloc can be written
in C (or C++) just by having my_malloc call
malloc [note: the fact that this is not
sensible is not relevant to an existence proof].
This has nothing to do with the fact that
char addresses have no alignment restrictions.

Point is that if you return such pointer to application
every attempt to dereference or store anything within
that memory region would produce undefined behavior
by your definition.

Not if the attempt to store and deference were made to
the start of the region.
unions are invented just to provide right alignment
for every member listed in common memory block.


Oh, alignment restrictions would have not prevent memory
allocator to be written, it would just make lot of legal
C code into undefined behavior.

Such as?

Any code that works on basis that char is aligned on any address,
such as typical memcpy C implementation.
I suppose you think it is impossible,
given two four byte ints, to copy the first byte
from the first int to the third byte of the
second int without reading anything smaller than an int.

Of course this is possible, except that accessing those int's would invoke
undefined behavior if they are not aligned.
example:
char buf[3];
double f;
char buf1[3];
memcpy(buf,buf1+2,1);
sizof(char) *must* always be equal to 1, but
the underlying hardware does not have to addresss
something as small as CHAR_BIT.

Sure. But CHAR_BIT is meant to be used for such cases when
char is smaller then minimum addressable unit because byte
is measurement unit for sizeof. So CHAR_BIT says
how fat is byte.
Char always have to fit in only one byte, no matter how byte is big.
That's why there are implementations where
sizeof(char) == sizeof(short) == sizeof(int) == sizeof(long)

However, the
abstact machine must address something as small
as CHAR_BIT, so the implementation may have to
perform some tricks.

Of course, it would be possible for implementation to
provide CHAR_BIT that is actually smaller then byte bits,
but such implementation can't be written in C.

Greetings, Bane.
 
J

Jordan Abel

If it's an unsigned char, I *think* the program (assuming
"#include <stdio.h>", and assuming whatever gyrations are required to
print an unsigned char even if sizeof(int)==1) is required to
print the same value twice.

Is sizeof(int) allowed to be 1 by a strict reading of the standard?
I thought that the entire range of unsigned char plus EOF have to be
uniquely representable in an int (for such things as getc, is...,
and so on) My interpretation of this is that int needs to be wider
than char.
 
J

Jordan Abel

I disagree. The standard does not mandate any behaviour here
and the implementation is free to take advantage of this.
(This is a good general principle. If there is no good
reason to mandate a behaviour the standard should not do so.)
As well as perverse implementations that do so just to
be a pain, there may be a good reason for this.
Consider:

int main() {

int b;
int a;
int c;
int d;

printf("%i\n", a);

b = c;

printf("%i\n", a);

return 0;
}


Now assume that for a particular implementation, b,a,c,d are in memory
in that order, ints are four bytes
and it is fastest for the implementation to
copy 8 bytes at a time. Then the compiler could note that copying the
8 bytes starting at c to the 8 bytes starting at b would have the
effect of assigning c to b and d to a. Since the second operation
is allowed, the faster operation is allowed and the compiler
could choose this.

By comp.lang.c standards this is not even a stretch.

Except that we've established that the standard does not use the
language "undefined behavior" - I think that in this case the
compiler would be free to perform this optimization in the absence
of the intervening printf, but would have to do some trickery to
make both printfs the same in the case that they are there - say,
reordering so that the assignment precedes the two printfs - or just
sucking it up and choosing the less efficient implementation - or,
since c is not initialized, it could simply write an arbitrary
16-byte area that has the four bytes corresponding to 'b' and those
corresponding to 'd' identical - it would be permitted to, say, zero
all four variables.
 
J

Jordan Abel

This is silly. Under this interpretation the code snippet

a = b;

invokes undefined behaviour. There is a limit to pedantry
even in comp.lang.c.

No, it quite clearly should fail to compile - after all, neither a
nor b have been declared.
 
K

Keith Thompson

Jordan Abel said:
Is sizeof(int) allowed to be 1 by a strict reading of the standard?
I thought that the entire range of unsigned char plus EOF have to be
uniquely representable in an int (for such things as getc, is...,
and so on) My interpretation of this is that int needs to be wider
than char.

This has been argued at length in the past. There are implementations
with sizeof(int)==1. As far as I know, they're all freestanding, so
they aren't required to provide getc().

On the other hand, I *think* a hosted implementation could legally
have sizeof(int)==1. The standard requires getc() to return EOF at
end-of-file, or the next character otherwise; it doesn't actually say
EOF has to be distinct from all character values. It means the usual
idiom for reading a file breaks down if the file contains characters
with the value -1, but you could work around that by checking feof().
 
B

Branimir Maksimovic

Flash Gordon said:
Branimir said:
Christian said:
William Hughes wrote:

Branimir Maksimovic wrote:

Mark McIntyre wrote:

On 26 Oct 2005 09:00:34 -0700, in comp.lang.c , "Branimir Maksimovic"

Keith Thompson wrote:
This is important in regard of what makes original poster conclude
that memcpy(&x,&y,sizeof(x)) should be always faster or equal then
memcpy(&x,&y,sizeof(x)-1).
^^^^^^^^^^^^^^^^^^^^^^^^^
Christian Bau (who was not the original poster) did not conclude this.
His point was that memcpy(&x,&y,sizeof(x)) *could* be faster
than memcpy(&x,&y,sizeof(x)-1).

Clearly memcpy parameter is not about number of copy operations, and
in this respect his conclusion is invalid, because if
memcpy(&x,&y,sizeof(x)-1) does not produce trap value, ^^^^^^^^^^^^^^^^^^^^^^^^^
implementation can use load register, store register,

Nope, you have to preseve the last byte.

What byte?
Implementation can do anything that does not change observable
behavior. Since you have stored something that is not
valid double object, last byte would not change observable behavior, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
because using x as a double further in program
produces undefined behavior anyway.

Example:

double x, y;
x = 0.0; y = 1.0 / 3.0;

((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Looks the same to me.

Oh original example which started whole discussion was lost. Sorry.
how about original example with:
memcpy (&x, &y, sizeof (x));

Christian Bau was responding to a bit about memcpy (&x, &y, sizeof (x) -
1); and his post looks entirely correct to me.
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
printf ("This implementation is broken!\n");

I stored the number 79 into the last byte of x. The memcpy is not
allowed to overwrite it, so it must contain the value 79 after the call
to memcpy. There is no undefined behavior. There might be undefined
behavior if I _would_ use x as a double, but I don't, so there is no
undefined behavior.

Come on, this has completely different semantics then original example.

This thread has been talking about both sizeof (x) and sizeof (x) - 1 for
ages.
You have created valid unsigned char object at a given address
and dropped memcpy with sizeof(x). Stop playing around.

All bytes can always be read as unsigned char values, An alternative
example would have been taking a copy of the byte that memcpy is not
allowed to change and verifying afterwards that it had not changed.

Even as I said that will shut up, couldn't resist to this one.
This is not enough to trick implementation to force preservation of said
byte.
Implementation can simply replace
if (((unsigned char *) &x) [sizeof (x) - 1] != 79)
with if (0) and change the byte without problem.
Since everything happens at same scope, this does not affect observable
behavior and here we are again :); one must to do something like this
instead:

double x,y;
((unsigned char *) &x) [sizeof (x) - 1] = 79;
memcpy (&x, &y, sizeof (x) - 1);
void foo(unsigned char*); /* some external function not visible in this
translation unit */
foo( ((unsigned char *) &x) + sizeof (x) - 1 );

Now implementation must preserve that byte because it does not knows
what happens in "foo". :)

But in case that we don't initialize the byte, trick is little bit
different:
double x,y;
unsigned char* p= ((unsigned char *) &x) +sizeof (x) - 1;
unsigned char t = *p;
memcpy (&x, &y, sizeof (x) - 1);
unsigned char foo(unsigned char*); /* some external function not visible
in this translation unit */
assert(foo(p)==t); /* this forces implementation to preserve
the byte since foo may or may not return same value */

Greetings, Bane.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top