(part 38) Han from China answers your C questions 
November 21st, 2008, 03:05 PM
| | |
Pointer to pointer
James Kuyper said: Quote: Quote: |
> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| >
The "%p" format specifier expects a void* argument. This is one of the
few places where a cast is routinely needed and perfectly correct:
>
printf("*a=%p *p=%p %c %s\n", (void*)*a, (void*)*p, **p, *p);
printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| Ben Bacarisse said: Quote: Quote: |
> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| Technical matter: %p expects arguments of type void * and the
conversion is not done automatically so you need to write:
>
printf("*a=%p *p=%p %c %s\n", (void *)*a, (void *)*p, **p, *p);
| I'm not sure James and Ben have this right, but I'd say it's more
probable I'm wrong here. Still, we'll see. CLC psychology dictates
that if I'm wrong, a dozen people with a grudge will be quick to
correct me.
6.2.5 (27) says the following:
"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."
And then a footnote for that says:
"The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions ..."
The OP is passing a (char *) to %p. Therefore, he doesn't need to
cast the printf() arguments to (void *).
This is the Unix execl() case in reverse. The function execl(),
for those terminally in ANSI/ISO C land, uses a null character
pointer - i.e., (char *)0 or (char *)NULL - to indicate the end
of its variable-length argument list.
execl("/path/file", "arg", "arg", "arg", NULL);
works if NULL is defined as ((void *) 0), whereas it's not
guaranteed to work if NULL is defined as 0.
Yours,
Han from China | 
November 21st, 2008, 03:25 PM
| | | | re: (part 38) Han from China answers your C questions
In article <92cac0c89d7a3ddd3428a5a149099b44@pseudo.borked.ne t>,
Borked Pseudo Mailed <nobody@pseudo.borked.netwrote: Quote: Quote: Quote: |
>> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| | | Quote:
>I'm not sure James and Ben have this right, but I'd say it's more
>probable I'm wrong here. Still, we'll see. CLC psychology dictates
>that if I'm wrong, a dozen people with a grudge will be quick to
>correct me.
| Okey dokey. Quote:
"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."
| The supposed problem here is that even though they have the same
representation, they may be passed to variadic functions in a
different way. One can imagine this really happening for, say,
ints and doubles, but that it should happen for char * and void *
is implausible. Quote:
>And then a footnote for that says:
>
"The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions ..."
| Footnotes are not normative, but this one strongly suggests that the
committee meant it to work.
-- Richard
--
Please remember to mention me / in tapes you leave behind. | 
November 21st, 2008, 03:55 PM
| | | | re: (part 38) Han from China answers your C questions
Borked Pseudo Mailed <nobody@pseudo.borked.netwrites: Quote:
Pointer to pointer
>
James Kuyper said: Quote: Quote: |
>> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| >>
>The "%p" format specifier expects a void* argument. This is one of the
>few places where a cast is routinely needed and perfectly correct:
>>
>printf("*a=%p *p=%p %c %s\n", (void*)*a, (void*)*p, **p, *p);
> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| >
Ben Bacarisse said: Quote: Quote: |
>> printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| >Technical matter: %p expects arguments of type void * and the
>conversion is not done automatically so you need to write:
>>
> printf("*a=%p *p=%p %c %s\n", (void *)*a, (void *)*p, **p, *p);
| >
I'm not sure James and Ben have this right, but I'd say it's more
probable I'm wrong here.
| In the end, my view is that there is no way to escape the effect of
the "shall be a pointer to void" in the description of %p. See
section 4 (Conformance) paragraph 2 -- violating a shall (that is not
a constraint) is undefined behaviour. Quote:
Still, we'll see. CLC psychology dictates
that if I'm wrong, a dozen people with a grudge will be quick to
correct me.
>
6.2.5 (27) says the following:
>
"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."
>
And then a footnote for that says:
>
"The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions ..."
>
The OP is passing a (char *) to %p. Therefore, he doesn't need to
cast the printf() arguments to (void *).
| Despite the same representation and alignment, printf (and friends)
may do something non-C-like and specifically permitted (by, say, the
hardware) only for void *s since the standard assures the
implementation that the argument will be a void * and nothing else.
I find it hard to image that it will fail (for a char *) but I also
find it much simpler to cast to void * as specified by the
specification of printf. If I were forced into an alternate, more
expensive, algorithm by a corner case in the standard I might be
tempted to document the choice and wing it, but that is not the case
here.
--
Ben. | 
November 21st, 2008, 03:55 PM
| | | | re: (part 38) Han from China answers your C questions
Borked Pseudo Mailed wrote: Quote:
Pointer to pointer
>
James Kuyper said: Quote: Quote: |
printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| The "%p" format specifier expects a void* argument. This is one of the
few places where a cast is routinely needed and perfectly correct:
printf("*a=%p *p=%p %c %s\n", (void*)*a, (void*)*p, **p, *p);
printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| >
Ben Bacarisse said: Quote: Quote: |
printf("*a=%p *p=%p %c %s\n", *a, *p, **p, *p);
| Technical matter: %p expects arguments of type void * and the
conversion is not done automatically so you need to write:
printf("*a=%p *p=%p %c %s\n", (void *)*a, (void *)*p, **p, *p);
| >
I'm not sure James and Ben have this right, but I'd say it's more
probable I'm wrong here. Still, we'll see. CLC psychology dictates
that if I'm wrong, a dozen people with a grudge will be quick to
correct me.
>
6.2.5 (27) says the following:
>
"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."
>
And then a footnote for that says:
>
"The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions ..."
| The tricky point is that while "it is meant to imply
interchangeabilty", it doesn't actually imply it. It's quite feasible
(easy, even) to invent a function calling convention where having the
same representation and alignment is not sufficient to ensure
interchangeability. To take the most direct approach, consider a
function calling convention where each argument is explicitly tagged
according to type. Less directly, consider an API that passes void*
pointers through a different method than char* pointers.
The key point is that while the footnote expresses the intent, the
actual words of the standard fail to mandate that the intent be
achieved. I'd be much happier if the standard said explicitly and
directly, in the normative text (footnotes are not normative), that
these type were interchangeable for the specified purposes. |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 225,662 network members.
|