K
Keith Thompson
S.Tobias said:Right.
extern char *pc;
void free(void *p);
free(pc); //correct
(Note: we don't need same representation requirement in the above
example. This requirement is necessary eg. for variadic arguments:
printf("%p", pc);
- no cast to void* required.)
No. I see no reason to require same alignment for types void* and char*,
because in function arguments they're passed by *value* (think conversion).
Similarly, long and char do not have to have same alignment, but we may
always use them in arguments "interchangeably":
extern long l;
extern char c;
int f_char(unsigned char c);
int f_long(unsigned long l);
f_char(l); //both calls correct
f_long(c);
No, we can't use long and char in arguments interchangeably. If
there's a prototype, the value is converted to the expected type;
you're not passing a char to f_long, you're passing a long. If
there's no visible prototype, the call f_long(c) invokes undefined
behavior.
Examples involving implicit conversions aren't relevant to the point.
In the call free(pc) above, you're not passing a char* to free(),
you're passing a void* value, the result of the implicit conversion of
the value of pc.
The interchangeability referred to in the footnote in C99 6.2.5
involves cases where something of one type is interpreted as another,
without a conversion (either explicit or implicit), such as a function
call with no prototype in scope, a call to a variadic function, or a
reference to a union member.
Suppose void* required 4-byte (word) alignment, but char* only
required 1-byte alignment (I'm referring to the required alignment for
a pointer object). Suppose the compiler has to generate different
code to access a byte-aligned char* than a word-aligned void*. Now
consider your call printf("%p", pc), where pc is a char*. The calling
code pushes the value of pc onto the stack at an odd address (assume
that there is a stack). The code inside printf that accesses the
argument expects a void*, so it uses an instruction that only works on
word-aligned values. Kaboom.
That's how differing alignments for void* and char* can cause problems
in parameter passing.
[snip]
(I'm not responding to the rest of your message, at least for now,
mostly because I don't have time to do it justice.)