Use of memcpy() to transfer from memory to a variable

M

Martin

Richard Heathfield said:
Well, I refer you to my earlier reply, in which I said that it is /not/
well-defined. See <[email protected]> for more details.

I can't see where you said that. In reply to my original question, viz. "Is
the following use of memcpy()
a well-defined way of so doing?" you replied "No, but it's not exactly
undefined either." I took that to mean it is not undefined.
 
R

Richard Heathfield

Martin said:
I can't see where you said that. In reply to my original question,
viz. "Is the following use of memcpy()
a well-defined way of so doing?" you replied "No, but it's not exactly
undefined either." I took that to mean it is not undefined.

There are several different kinds of behaviour described in the
Standard. They are:

* Unspecified behavior --- behavior, for a correct program construct
and correct data, for which the Standard imposes no requirements.

* Undefined behavior --- behavior, upon use of a nonportable or
erroneous program construct, of erroneous data, or of
indeterminately-valued objects, for which the Standard imposes no
requirements. [...]

* Implementation-defined behavior --- behavior, for a correct program
construct and correct data, that depends on the characteristics of
the implementation and that each implementation shall document.

* Locale-specific behavior --- behavior that depends on local
conventions of nationality, culture, and language that each
implementation shall document.

(C99 may add more - I haven't checked.)

If the Standard *fully* describes the behaviour of the construct, it is
considered to be "well-defined". Otherwise, the behaviour is one of the
others described above. It isn't locale-specific, for reasons that I
hope are obvious. It isn't implementation-defined, because the
implementation is not required to document which value your object will
take. The remaining possibilities are: undefined, unspecified, and
well-defined. It isn't well-defined because the value your object will
have after your memcpy cannot be determined solely by reference to the
Standard. So it's either unspecified or undefined.

To judge it 'undefined' would, I think, be harsh. After all, you
specified that sizeof(long) was 4, and I think it's fair to assume that
you would be happy to specify that CHAR_BIT is 8, so we're talking
about an object exactly 32 bits wide, and long ints must be at least
that wide anyway. You are giving precise values to three of the four
bytes in the long int, and the fourth is known to contain 0-bits. In no
case are you setting any byte in such a way that the sign bit will be
set, so that prospective complication is ruled out. So you're going to
end up with some legal value or other in your long int. The exact value
you get will depend, basically, on endianness (byte ordering), for
which the Standard doesn't impose any requirements on the
implementation.

So in /my/ judgement, the behaviour is neither well-defined,
implementation-defined, undefined, or locale-specific. That leaves
'unspecified' as the only remaining option.

Others here may disagree, of course!
 
H

Hallvard B Furuseth

Richard said:
To judge it 'undefined' would, I think, be harsh. After all, you
specified that sizeof(long) was 4, and I think it's fair to assume that
you would be happy to specify that CHAR_BIT is 8, so we're talking
about an object exactly 32 bits wide, and long ints must be at least
that wide anyway.

Right, I hadn't noticed that.
You are giving precise values to three of the four
bytes in the long int, and the fourth is known to contain 0-bits. In no
case are you setting any byte in such a way that the sign bit will be
set, so that prospective complication is ruled out.

Not in the example values, but those were just an example.
Another way to avoid sign bit complications is to use unsigned long.
So you're going to
end up with some legal value or other in your long int.

Well, data which represents a legal value if the compiler deigns to
notice it.

You missed one point: He stored that in a way - via a char type - which is
a valid way to access that location, which tells the compiler that there
is a new value in the variable's location. I think. Compare with:
long foo()
{
long v = 0;
*((short *)&v) = 123;
return v;
}
which may return 0 - and it does, with gcc-4 -O2.
Replace short with char and it returns nonzero.


Personally I've begun to run scared and stuff "volatile" into code like
that, even though that doesn't help definedness. I've lost track of
things like whether e.g. memcpy vs. just storing directly into the long
makes a difference. Or if the compiler can get anal and decide that a
long can't have been stored because only 3 bytes were stored. I'm
fairly sure it's bad to store partial values, but maybe I've got that
from another context. Unions, maybe.


BTW, I wouldn't trust a modern "C89" compiler to still be using C89
semantics with stuff like this, if there really is a difference other
than different terminology than C99. And assuming the semantics is
different, I suspect more aggressive optimizations (valid in C89) are a
more noticeable difference anyway, with regards to bit/byte-fiddling.
 
M

Martin

Hallvard said:
A real-world example I vaguely remember from earlier discussions, I
think before C99, which the OP's example can produce: Sign bit 1, all
other bits 0, when LONG_MIN == -LONG_MAX, on a two's complement machine.

All the variable defined in the program I posted here are unsigned, so can I
assume there is no danger of a trap representation?
 
K

Keith Thompson

Martin said:
All the variable defined in the program I posted here are unsigned, so can I
assume there is no danger of a trap representation?

No, unsigned types bigger than unsigned char can have padding bits and
trap representations (though I don't know of any implementations where
they actually do).
 
H

Hallvard B Furuseth

Martin said:
All the variable defined in the program I posted here are unsigned, so can I
assume there is no danger of a trap representation?

Not when it also has the minimum size allowed for an unsigned long. I
seem to have been far too tired when I originally read this thread, I
knew your variable was long and not unsigned long. Maybe someone said
long elsewhere.
 

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

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top