Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > printf() and void *

Reply
Thread Tools

printf() and void *

 
 
CBFalconer
Guest
Posts: n/a
 
      03-04-2008
Barry Schwarz wrote:
> Peter Nilsson <(E-Mail Removed)> wrote:
>> Barry Schwarz <(E-Mail Removed)> wrote:
>>> ...
>>> scanf must accept many different kinds of pointers.
>>> %s requires a char*, %d requires an [int], etc.

>
> Interesting that your reader didn't quote what I wrote.


Hm. According to mine, it did.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.


--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
 
 
 
Peter Nilsson
Guest
Posts: n/a
 
      03-04-2008
Barry Schwarz <(E-Mail Removed)> wrote:
> Peter Nilsson wrote:
> > >*%s requires a char*, %d requires an [int], etc.

>
> Interesting that your reader didn't quote what I wrote.


My bad. Let me start afresh...

Barry Schwarz <(E-Mail Removed)> wrote:
> Ioannis Vranos <(E-Mail Removed)> wrote:
> > I recall from previous discussions here, that we must
> > cast a non-void pointer to void * before printing its
> > value with printf("%p"). Is it true, and if yes why?

>
> Different types of object pointers are allowed to have
> different sizes and different representations. But you
> are allowed to convert (explicitly or implicitly) between
> any of these types and void* with no loss of information.
>
> scanf must accept many different kinds of pointers.
> %s requires a char*, %d requires an int*, etc.


Currently yes.

> Therefore,


This is the key word for me.

> it is not possible to have a rule that says any pointer
> in the variadic portion of the argument list would be
> "promoted" to void*.


In conjunction with the current rules of %d expecting int *,
quite so. But that isn't to say that the automatic promotion
to void * could not work in principle: %s, %d, etc... would
simply take a void *. The original argument expression would
naturally have to be of the correct type though.

> (There is such a rule that says short and char are
> promoted to int and float is promoted to double in the
> variadic portion of an argument list.) [scanf could
> have been designed to accept void pointers across the
> board


Indeed. This could apply to any pointer argument supplied
as the variadic component to variadic function.

> but then compilers could not optionally check the
> arguments against the conversion specifications.]


Why would _that_ be an issue?

For starters, most compilers that I've used don't bother;
secondly, compilers already have to do the static type
analysis to implement default argument promotion anyway.

> Rather than provide printf with a slew of conversion
> specifications (which could have also allowed function
> pointers to be printed),


Just one would suffice. [Accepting say void (*)(void).]

> %p is used for all object pointers after they have been
> converted to void*. Since there is no automatic conversion
> to void* (for the variadic portion of an argument list),
> you must direct the compiler to perform the conversion by
> casting the value.


What I read (perhaps hastily) was that this automatic
conversion was not (could never have been) a possible option
for the C language.

I wouldn't want it to be, but I can't see any principle
reason for it not working.

--
Peter
 
Reply With Quote
 
 
 
 
ymuntyan@gmail.com
Guest
Posts: n/a
 
      03-04-2008
On Mar 3, 2:03 pm, Harald van Dijk <(E-Mail Removed)> wrote:
> On Sun, 02 Mar 2008 23:48:33 -0800, ymuntyan wrote:
> > On Mar 3, 12:19 am, Harald van Dijk <(E-Mail Removed)> wrote:
> >> On Sun, 02 Mar 2008 19:45:29 -0800, Peter Nilsson wrote:
> >> > Harald van Dijk <(E-Mail Removed)> wrote:
> >> >> ... [the] example prints the representation of a function pointer,
> >> >> not its value.

>
> >> > It's value is determined by the representation.

>
> >> Of course, but that's true for all types. Should we start printing 1.01
> >> as a series of bytes too, then?

>
> > Isn't it what "binary file formats" is about?

>
> I meant printing the series of bytes as hexadecimal numbers, which is not
> what binary file formats are about.


Attach any file to an email and you get that. I meant,
dumping bytes in hex format isn't necessarily a bad idea,
even for 1.01 (but "binary" wasn't the right word here,
true).

>
> >> >> If multiple function pointer representations exist for one value,
> >> >> there is no portable way to print the value in such a way that the
> >> >> different representations become indistinguishable.

>
> >> > How is this any different to the case for %p? The only thing you're
> >> > guaranteed is that if you read via %p you'll get a pointer that
> >> > compares equal to the original.

>
> >> If you print the same value to printf twice, you can be sure you get
> >> the same string twice. If you print the representation of two identical
> >> values twice, you can't be sure you get the same string twice.

>
> > You can not be sure that you'll get two identical strings from
> > printf("%p\n%p\n", p, p).

>
> The standard states that "the value of the pointer is converted to a
> sequence of printing characters, in an implementation-defined manner."
> This, by my reading, does not allow anything other than the value of the
> pointer to have an effect on the output. In particular, it does not allow
> the representation of the pointer (when multiple representations of the
> same value exist) to have an effect.


I am not sure if what you're saying is right (why can't an
implementation
print the "padding" bits from the pointer object you're passing to it,
even if there are those "padding" bits which may be set in different
ways without changing the value?), but it's certainly true that
"""You can not be sure that you'll get two identical strings from
printf("%p\n%p\n", p, p)"""
It may attach a time stamp to the pointer, or print some random
bits from /dev/random or whatever.

Yevgen
 
Reply With Quote
 
David Tiktin
Guest
Posts: n/a
 
      03-04-2008
On 03 Mar 2008, Richard Heathfield <(E-Mail Removed)> wrote:

> David Tiktin said:
>
>> On 02 Mar 2008, Richard Heathfield <(E-Mail Removed)> wrote:
>>

> <snip>
>>>
>>> Well, no pointer value can be printed portably, since the output
>>> associated with %p is implementation-defined.

>>
>> I'm a little unclear on the point you're making here. I would
>> have said that the code:
>>
>> #include <stdio.h>
>> #include <limits.h>
>>
>> int main(void)
>> {
>> printf("%d\n", INT_MAX);
>>
>> return 0;
>> }
>>
>> is a completely portable way to print the value of INT_MAX even
>> though what's printed is obviously implementation defined.

>
> Right - the technique is portable, but the value isn't.
>
> <snip>
>
>> Can't you write to a
>> text file portably in C even though the result is implementation
>> defined?

>
> Again, the technique is portable, but the value isn't. Consider:
>
> #include <stdio.h>
>
> int main(void)
> {
> FILE *fp = fopen("foo.txt", "w");
> if(fp != NULL)
> {
> if(fputs("A\n", fp) != EOF && fclose(fp))
> {
> puts("All is well.");
> }
> }
> return 0; /* if fputs failed, the stream will be closed on exit!
> */
> }
>
> If "All is well" is displayed (under any conforming hosted
> implementation), we have created a text file, which in C terms
> contains one line comprising 'A' and a newline character. So the
> technique is portable.
>
> But what have we actually created, in what we might call absolute
> terms? On a PC under Windows, the file will contain three bytes,
> with values 65, 13, and 10 (obviously I'm using decimal
> representation here). On an old-style Mac, it would contain just
> two bytes: 65, 13. On a Linux box (or, I *think*, a modern Mac),
> it would contain 65, 10. On an IBM mainframe, well, don't ask(!),
> but to start off with, that 'A' would be 193 rather than 65. The
> point is that, whilst the output can be interpreted consistently
> within the machine/OS/implementation combination, moving that file
> to another (disparate) system will (or at least may) result in
> that interpretation becoming invalidated unless some kind of data
> massage is performed.


Yes, this is exactly what I had in mind, which is why I brought up
this issue. The effect is "implementation defined," not undefined.
In your reply to the OP, you seemed to be saying that portable code
can't rely on implementation defined behavior. That seemed to me too
strong.

> So I guess it all depends on what we mean by "portable"!


But *do* we mean by "portable code," code that, among other things,
doesn't rely on any implementation defined behavior? I'm saying that
it couldn't mean that (even in part) or all (or almost all?) I/O
would be non-portable. That doesn't seem right to me. One of the
reasons I like C is because it has portable I/O libraries. I don't
have to #ifdef my code if use stdio.h defined functions. So why
would you say that printing the value of a data pointer using %p is
not portable? It can't just be that the output is implementation
defined.

As an operational definition, I would say portable code is code there
is no reason to conditionally compile based on the platform the code
will run on. You won't see portable code surrounded by:

#if defined(_WIN32)
...
#elif defined(_LINUX)
...
#else
#error "Unknown platform."
#endif

although portable code may make use of macros #defined in sections
such as this. (The conditionally compiled sections may make other
sections of code portable.)

By this definition, printing the value of a pointer with %p is
portable, as it using the Standard Library functions to read and
write text files. If you make certain assumptions about what will
happen in these cases, other parts of your code may become non-
portable, for instance, if you assume that %p will print exactly 8
hex digits on all platforms. But the presence of implemenation
defined behavior by itself doesn't make using %p automatically non-
portable.

Dave

--
D.a.v.i.d T.i.k.t.i.n
t.i.k.t.i.n [at] a.d.v.a.n.c.e.d.r.e.l.a.y [dot] c.o.m
 
Reply With Quote
 
Richard Heathfield
Guest
Posts: n/a
 
      03-04-2008
David Tiktin said:

<snip>

> But *do* we mean by "portable code," code that, among other things,
> doesn't rely on any implementation defined behavior?


In comp.lang.c we are very quick to say that such-and-such is, or is not,
portable, but in practice portability might be considered a continuum (in
several different dimensions) rather than a binary attribute of a given
code construct.

Code that doesn't rely on /any/ implementation-defined (or unspecified or
undefined) behaviour - that is, what the Standard calls a "strictly
conforming program" - is maximally portable, but even such "ideal" code
depends on the very characteristics of the platform that support its
ability to produce output (if indeed it does produce output, which need
not apply to library code, of course).

In practice, code can be *very* portable without necessarily being strictly
conforming. For example, the assumption that CHAR_BIT is 8 works on a
goodly selection of platforms (although of course not everywhere). If a
program depends for its correct working on the (presumably asserted or
otherwise validated) assumption that CHAR_BIT is 8, but is otherwise free
of implementation-defined behaviour, is it portable or not? Answer: it's
portable to platforms on which the assumption is valid, and not to those
on which it is not valid - so the program is portable *to a degree*.

Although it is certainly true that relying on the implementation-defined
behaviour of <foo> renders your code non-portable, this is only in an
absolute sense. It is very likely that the code will still work just fine
on a large number of platforms.

In the case in point, however, which is far more boring than you're giving
it credit for, I was only talking about the value being non-portable, in
the sense that you're not guaranteed to get the same output for the same
program on two different platforms (or even for two prints of the same
pointer value on the same program within the same run). I'd have thought
this was self-evidently true, and it's also mind-numbingly dull.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
 
Reply With Quote
 
Morris Dovey
Guest
Posts: n/a
 
      03-04-2008
Richard Heathfield wrote:

> Code that doesn't rely on /any/ implementation-defined (or unspecified or
> undefined) behaviour - that is, what the Standard calls a "strictly
> conforming program" - is maximally portable, but even such "ideal" code
> depends on the very characteristics of the platform that support its
> ability to produce output (if indeed it does produce output, which need
> not apply to library code, of course).


Erm, yes. Thank you for making that so clear.

ROFL

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto/Projects/Monitor/
 
Reply With Quote
 
Harald van D캐k
Guest
Posts: n/a
 
      03-04-2008
On Mon, 03 Mar 2008 23:33:01 -0800, ymuntyan wrote:
> On Mar 3, 2:03 pm, Harald van D캐k <(E-Mail Removed)> wrote:
>> On Sun, 02 Mar 2008 23:48:33 -0800, ymuntyan wrote:
>> > You can not be sure that you'll get two identical strings from
>> > printf("%p\n%p\n", p, p).

>>
>> The standard states that "the value of the pointer is converted to a
>> sequence of printing characters, in an implementation-defined manner."
>> This, by my reading, does not allow anything other than the value of
>> the pointer to have an effect on the output. In particular, it does not
>> allow the representation of the pointer (when multiple representations
>> of the same value exist) to have an effect.

>
> I am not sure if what you're saying is right (why can't an
> implementation
> print the "padding" bits from the pointer object you're passing to it,
> even if there are those "padding" bits which may be set in different
> ways without changing the value?), but it's certainly true that """You
> can not be sure that you'll get two identical strings from
> printf("%p\n%p\n", p, p)"""
> It may attach a time stamp to the pointer, or print some random bits
> from /dev/random or whatever.


On such an implementation, what's converted to a sequence of printing
characters is not the value of the pointer. It's the value of the pointer,
plus part of the representation and/or random bits. I consider that in the
same category as why putchar('e') isn't allowed to print "hello", even
though printing "hello" would also have caused 'e' to be written.
 
Reply With Quote
 
ymuntyan@gmail.com
Guest
Posts: n/a
 
      03-04-2008
On Mar 4, 12:14 pm, Harald van Dijk <(E-Mail Removed)> wrote:
> On Mon, 03 Mar 2008 23:33:01 -0800, ymuntyan wrote:
> > On Mar 3, 2:03 pm, Harald van Dijk <(E-Mail Removed)> wrote:
> >> On Sun, 02 Mar 2008 23:48:33 -0800, ymuntyan wrote:
> >> > You can not be sure that you'll get two identical strings from
> >> > printf("%p\n%p\n", p, p).

>
> >> The standard states that "the value of the pointer is converted to a
> >> sequence of printing characters, in an implementation-defined manner."
> >> This, by my reading, does not allow anything other than the value of
> >> the pointer to have an effect on the output. In particular, it does not
> >> allow the representation of the pointer (when multiple representations
> >> of the same value exist) to have an effect.

>
> > I am not sure if what you're saying is right (why can't an
> > implementation
> > print the "padding" bits from the pointer object you're passing to it,
> > even if there are those "padding" bits which may be set in different
> > ways without changing the value?), but it's certainly true that """You
> > can not be sure that you'll get two identical strings from
> > printf("%p\n%p\n", p, p)"""
> > It may attach a time stamp to the pointer, or print some random bits
> > from /dev/random or whatever.

>
> On such an implementation, what's converted to a sequence of printing
> characters is not the value of the pointer. It's the value of the pointer,
> plus part of the representation and/or random bits. I consider that in the
> same category as why putchar('e') isn't allowed to print "hello", even
> though printing "hello" would also have caused 'e' to be written.


Suppose it's a PC with 32-bit pointers, without multiple
representations
for the same value, where cast to unsigned int and back is well-
defined.
The following function would be a conforming way to print void* in
printf:

void print_pointer(void *p)
{
static unsigned counter;
printf("'''%08x%08x'''", (unsigned)p, counter++);
}

It prints "extra" here, yes. But that "extra" is not forbidden.
I have no idea why one would do that, but it certainly would
be conforming. How is appending a number worse than prepending
"0x" or printing "(nil)"? fputc() is different, it doesn't have
this "implementation-defined manner" freedom. It "writes the
character", not a sequence of characters obtained in an
implementation-defined manner.

Whether it's allowed to use the bits from the representation,
I don't know. I'd think it is, but it's a different story
anyway.

Yevgen
 
Reply With Quote
 
Harald van D캐k
Guest
Posts: n/a
 
      03-04-2008
On Tue, 04 Mar 2008 10:52:36 -0800, ymuntyan wrote:
> Suppose it's a PC with 32-bit pointers, without multiple representations
> for the same value, where cast to unsigned int and back is well-
> defined.
> The following function would be a conforming way to print void* in
> printf:
>
> void print_pointer(void *p)
> {
> static unsigned counter;
> printf("'''%08x%08x'''", (unsigned)p, counter++);
> }
>
> It prints "extra" here, yes. But that "extra" is not forbidden. I have
> no idea why one would do that, but it certainly would be conforming. How
> is appending a number worse than prepending "0x"


In your example, what's printed depends on more than the pointer value.
The pointer value is what must be formatted. Not the pointer value and
some other data.

> or printing "(nil)"?


That's fine. It depends only on the value of the pointer, nothing else.

> fputc() is different, it doesn't have this "implementation-defined
> manner" freedom.


And the *printf functions have no freedom in choosing what data to use to
print pointers. They happen to have freedom in choosing how to use that
data, but that's a different issue.

> It "writes the character", not a sequence of characters
> obtained in an implementation-defined manner.


Right. The character is printed. Not the character and some other data.

If putchar('e') prints "hello", it has written the character. It also
happened to have written other data, but the description of putchar
doesn't say it can't.

It's clear to both of us this logic is invalid.

If printf("%p", p) includes a random number in its output, it has
formatted the pointer value. It also happened to have formatted other
data, but the description of fprintf doesn't say it can't.

I don't seem to be able to convince you this logic is equally invalid.

> Whether it's allowed to use the bits from the representation, I don't
> know. I'd think it is, but it's a different story anyway.

 
Reply With Quote
 
ymuntyan@gmail.com
Guest
Posts: n/a
 
      03-04-2008
On Mar 4, 1:08 pm, Harald van Dijk <(E-Mail Removed)> wrote:
> On Tue, 04 Mar 2008 10:52:36 -0800, ymuntyan wrote:
> > Suppose it's a PC with 32-bit pointers, without multiple representations
> > for the same value, where cast to unsigned int and back is well-
> > defined.
> > The following function would be a conforming way to print void* in
> > printf:

>
> > void print_pointer(void *p)
> > {
> > static unsigned counter;
> > printf("'''%08x%08x'''", (unsigned)p, counter++);
> > }

>
> > It prints "extra" here, yes. But that "extra" is not forbidden. I have
> > no idea why one would do that, but it certainly would be conforming. How
> > is appending a number worse than prepending "0x"

>
> In your example, what's printed depends on more than the pointer value.
> The pointer value is what must be formatted. Not the pointer value and
> some other data.
>
> > or printing "(nil)"?

>
> That's fine. It depends only on the value of the pointer, nothing else.


And also on the will of implementor who can write "(nil)" or
"0" or what else he likes. Anyway, you claim that the format
of %p output must not depend on the program state; I claim it
may depend on the program state. E.g. implementation could
choose the format on startup, like print "(nil)" if program
started on Monday and print "0" if program started on other
day. Or print "(nil)" when printf is *called* on Monday. Or
append a random number.

I guess we can just agree to disagree here

> > fputc() is different, it doesn't have this "implementation-defined
> > manner" freedom.

>
> And the *printf functions have no freedom in choosing what data to use to
> print pointers. They happen to have freedom in choosing how to use that
> data, but that's a different issue.
>
> > It "writes the character", not a sequence of characters
> > obtained in an implementation-defined manner.

>
> Right. The character is printed. Not the character and some other data.
>
> If putchar('e') prints "hello", it has written the character. It also
> happened to have written other data, but the description of putchar
> doesn't say it can't.


Description of files says it can't. What's written can be read
back and you'll know that more than one or a wrong character was
written. If it can't be read, then there is simply nothing to
talk about.

> It's clear to both of us this logic is invalid.
>
> If printf("%p", p) includes a random number in its output, it has
> formatted the pointer value. It also happened to have formatted other
> data, but the description of fprintf doesn't say it can't.


So printf("%p") *is* different in this respect from putchar().

Yevgen
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What is the difference between void proba(); and void proba(void); ??? PencoOdStip@gmail.com C++ 1 05-23-2007 07:12 PM
what is the difference, void func(void) and void fucn() noblesantosh@yahoo.com C Programming 5 07-22-2005 04:38 PM
"void Method()" vs "void Method(void)" Ollej Reemt C++ 7 04-22-2005 03:47 AM
returning a void (*)(void) Sergio C++ 6 01-05-2005 08:30 PM
`void **' revisited: void *pop(void **root) Stig Brautaset C Programming 15 10-28-2003 09:03 AM



Advertisments