J
James Kuyper
Now, what happens when this struct is embedded in a binary file stored
in a character array "buffer[]" such that its position "i" is not
guaranteed to be aligned on the same boundary that
Mystract *instance2 = malloc(sizeof(Mystruct));
would have used, but will always be on a multiple of 2.
1. Will this always work?
function1((Mystruct *) &(buffer));
(Eric Sosman wrote
Not "always," no. 6.3.2.3p7: "A pointer to an object type
may be converted to a pointer to a different object type. If the
resulting pointer is not correctly aligned for the referenced
type, the behavior is undefined. [...]" There's no guarantee
that the alignment of `buffer' suffices for `Mystruct'.
On further consideration, how does one know what "correctly aligned"
means for a given struct? Consider these two examples:
typedef struct {
uint16_t one;
uint16_t two;
uint16_t three;
uint16_t four;
} Mystruct4;
I've noticed that you routinely fail to provide citations for who wrote
the things that you quoted. That's rather rude to the persons who said
it,, and also inconvenient for the rest of us trying to figure out who
said what. It can also get you into legal trouble in some contexts,
thought usenet posts are so easily forged that it would be hard to
imagine that happening in this context.
I deny permission to any and all authors to quote any text that I write
without appropriate citation. Don't bother responding if you're not
willing to provide it.
Taking into account the various answers in this thread to the preceding
question it would seem that there is still no safe (safe meaning here
"code that will work on any platform") method to use a C struct
to extract binary data directly from memory, since the compiler can
throw in padding and alignment requirements whenever it feels like it.
Not quite - for instance, padding is not allowed at the beginning, and
the alignment requirement for an aggregate object (a struct or an array)
must be at least as strict as it is for any of the members of the
aggregate. Still, the basic point remains - the standard does not
provide enough guarantees to allow the use such a struct to read date
directly from a file.
Even if the data is reduced to byte representation, something like this
(I know it isn't the same as Mystruct4 above):
typedef struct {
uint8_t one[2]; /* actually uint16_t */
uint8_t two[4]; /* actually uint32_t */
int8_t three[2]; /* etc. */
int8_t four;
} Mystruct4b;
it seems not to be safe to pass a "Mystruct4b *" pointer to a function
which references this data at an arbitrary location in memory. Instead
the only safe method is to pass "char *" pointers and take the data
apart with memcpy() at a very low level, moving it from memory to the
structure, or vice versa.
Correct. Because of these things that are not guaranteed, C structs
should be considered as suitable only for use for in-memory objects, not
for reading or writing from files.
What an odd situation. I would have thought with all of the data that
does show up in C programming as "a series of bytes in a buffer arranged
in some particular manner", that is, pretty much any data which is
passed from machine to machine, C would have developed a method for
simplifying this sort of code. Perhaps something along these lines
I agree that some such feature would be useful. But there are problems
with the various possible alternatives.
/* declare memory organization, no padding, no alignment requirement */
typedef memstruct {
uint16_t one;
uint32_t two;
int16_t three;
uint8_t four;
} Mystruct4c;
Specifically so that one could pass a "Mystruct4c *" pointer to a
function, like so:
myfunction3a(Mystruct4c *ptr){
ptr->two = 5;
printf("value of three:%d\n",ptr->three);
}
The fundamental problem with such a feature is that &ptr->two is not
necessarily correctly aligned for a uint32_t object. This is not a
serious problem on some architectures, where alignment is a mere
efficiency issue. However, there are other platforms where the hardware
imposes very strict alignment requirements.
In code where Mystruct4c is in scope, and where the derivation of the
pointer from an object of that type is perfectly clear, the compiler
could write special code equivalent to using memcpy() to copy from
ptr->two to correctly aligned memory, and then passing the value stored
in that temporary to printf(); for writing to such an object, a pointer
to correctly aligned memory could be used, and them the equivalent of
memcpy() could be used to copy from the temporary object back to the
incorrectly aligned memory. However, consider code like the following:
uint32_t default = 42;
uint32_t *p = default < ptr->two ? &default : &ptr->two;
myfunc(p);
How can myfunc know how to use 'p', when it might be either a pointer to
memory which is correctly aligned for a uint32_t, or a misaligned
pointer? Also, using pointers to temporary correctly-aligned pieces of
memory would mess up comparisons of pointers for equality or relative order.