Printing a NULL pointer

R

Richard Tobin

In all real-world implementations the NULL pointer is all-bits zero.
(Someone will post a counter-example if I'm wrong.)
[/QUOTE]
See FAQ 5.17

Thanks, an interesting list. But I don't think any of the machines
listed as having non-zero null pointers are in the real world any
more. In the case of the Primes, I certainly hope not.

-- Richard
 
D

Dik T. Winter

....
> But you know how %d will printf and how it will scanf back
> in. You know that you can use spaces, letters, or
> punctuation to separate a %d-generated number from other
> data. You do *not* know (from the standard) what %p will or
> won't print so you don't know what delimiters, if any, are
> safe to use. So, you can't use delimiters.

You can. You are sure (from the standard) that the output will not include
\t, \r or \n. %p is guaranteed to give only printable characters, and those
three are not; they are control characters. However I always doubted the
usefulness of being able to read pointers with %p, except, perhaps, in
debuggers.
> And how the heck do you print a function pointer? It's not
> guaranteed to fit in a void*, right?

There is a good reason for that. There are systems where function pointers
simply are not compatible with data pointers. For example, when they are
much wider. But what is a good reason to print a function pointer?
 
N

Neil Kurzman

Is there any way by which user can determine what is the internal
representation for a NULL pointer ? I am asking this because,
sometimes during debugging the memory dump is analysed. In that
case it would be difficult to find it is a NULL pointer or not.

Set a Pointer to NULL then look at the memory dump.
Theoretical vs Practical.
 
M

Michael Wojcik

printf("%p\n", (void*)NULL);

is very likely to print a legible form of the representation of a null
pointer (which is very likely to be all-bits-zero).

Though not on the ever-lovin' AS/400.[1] This example also shows
that the %p format on the AS/400 contains both colons and spaces,
and so meets the fears of some other posters in this thread.

(On the other hand, I ran across a post from Dan Pop noting that
length and precision specifiers are not permitted with %p; if true,
that satisfies one worry that's been posted.)
If "very likely"
isn't good enough, several followups have shown how to break the
representation down into a sequence of bytes.

Yep. 16 bytes, in the case of the '400. The '400 also offers a
cozy 2**127-1 pointer trap representations, though - mirabile dictu -
its null pointer representation is all-bits-zero.


1. http://groups-beta.google.com/group/comp.lang.c/msg/664a3c0c955d17f3

See also:
http://groups-beta.google.com/group/comp.lang.c/msg/b7438cf53aa68a6b
http://groups-beta.google.com/group/comp.lang.c/msg/f29b7dc93bdbf187

--
Michael Wojcik (e-mail address removed)

The surface of the word "profession" is hard and rough, the inside mixed with
poison. It's this that prevents me crossing over. And what is there on the
other side? Only what people longingly refer to as "the other side".
-- Tawada Yoko (trans. Margaret Mitsutani)
 
L

Lawrence Kirby

On Thu, 16 Jun 2005 15:33:24 +0000, Michael Wojcik wrote:

....
(On the other hand, I ran across a post from Dan Pop noting that
length and precision specifiers are not permitted with %p; if true,
that satisfies one worry that's been posted.)

A precision specifier is certainly not permitted with %p (it givbes
undefined behaviour) but as far as I can see minimum field width is.
The only conversion specifier you can't use a minimum field width
for is %%.

Lawrence
 
A

Anonymous 7843

But what is a good reason to print a function pointer?

Depends on your definition of good, but how about
debugging a non-portable feature like dynamic libraries?

Technically there is no need to be able to print object pointers
either, yet we can do so.
 
J

Jean-Claude Arbaut

Le 17/06/2005 02:12, dans aAose.225$SF5.214@fed1read07, « Anonymous 7843 »
Depends on your definition of good, but how about
debugging a non-portable feature like dynamic libraries?

Technically there is no need to be able to print object pointers
either, yet we can do so.

Is there a good reason appart from debugging ? I can't see one, but
I may be too tired at 3:15 local :)
 
D

Dik T. Winter

>
> Depends on your definition of good, but how about
> debugging a non-portable feature like dynamic libraries?

But what do you think is a good way to print a function pointer when it
is, say, twice as wide as an object pointer? While, in general, object
pointers are as wide, or smaller than a void*, a function pointer can
be much wider.
 
K

Keith Thompson

Dik T. Winter said:
But what do you think is a good way to print a function pointer when it
is, say, twice as wide as an object pointer? While, in general, object
pointers are as wide, or smaller than a void*, a function pointer can
be much wider.

Here's a function that returns a hexadecimal image of any object,
given its address and its size in bytes. The caller needs to free()
the result after using it.

#define NIBBLES_PER_BYTE ((CHAR_BIT+3)/4)

char *hex_image(void *addr, size_t len)
{
char *result = malloc(NIBBLES_PER_BYTE * len + 1);
unsigned char *in = addr;
char *out = result;
size_t i;

if (result == NULL) return NULL;

for (i = 0; i < len; i ++) {
sprintf(out, "%0*x", NIBBLES_PER_BYTE, *in);
in ++;
out += NIBBLES_PER_BYTE;
}
return result;
}

It can be simplified a little if you don't mind assuming CHAR_BIT==8.
 
R

Richard Bos

Depends on your definition of good, but how about
debugging a non-portable feature like dynamic libraries?

If you're debugging non-portable features, using other non-portable
features to do so is perfectly sensible.

Anyway, you can always just print the representation in memory, using an
unsigned char *. It's not guaranteed to be unique, but at least you'll
have _a_ representation.

Richard
 
L

Lawrence Kirby

But what do you think is a good way to print a function pointer when it
is, say, twice as wide as an object pointer? While, in general, object
pointers are as wide, or smaller than a void*, a function pointer can
be much wider.

C allows a function pointer to be cast to any other type of function
pointer (and back again). So you could have a printf() conversion
specifier, say %P that takes a function pointer of a particular type, say
void (*)(void). So

printf("%P\n", (void (*)(void))main);

Lawrence
 
A

Anonymous 7843

But what do you think is a good way to print a function pointer when it
is, say, twice as wide as an object pointer? While, in general, object
pointers are as wide, or smaller than a void*, a function pointer can
be much wider.

I like Unleashed Guy's %P idea. (Which is what I was thinking
all along, but I grew tired of dtw's platonic methodry more slowly
than usual, which is a credit to him.)

%P is a logical extension to existing practice, doesn't break
existing conforming programs, and is very easy to implement,
outright trivial on flat address space machines.

To be truly radical, I advocate amending the bit about varargs
promotion. Function pointers used in a varargs (or non-prototype
context) should be implicitly converted to void(*)(void) so you
can pass function pointers to printf w/o a cast.
 
T

Tim Rentsch

Keith Thompson said:
Dik T. Winter said:

But what do you think is a good way to print a function pointer when it
is, say, twice as wide as an object pointer? While, in general, object
pointers are as wide, or smaller than a void*, a function pointer can
be much wider.

Here's a function that returns a hexadecimal image of any object,
given its address and its size in bytes. The caller needs to free()
the result after using it.

#define NIBBLES_PER_BYTE ((CHAR_BIT+3)/4)

char *hex_image(void *addr, size_t len)
{
char *result = malloc(NIBBLES_PER_BYTE * len + 1);
unsigned char *in = addr;
char *out = result;
size_t i;

if (result == NULL) return NULL;

for (i = 0; i < len; i ++) {
sprintf(out, "%0*x", NIBBLES_PER_BYTE, *in);
in ++;
out += NIBBLES_PER_BYTE;
}
return result;
}

As compiler technology has gotten better, one of the rules I've
had to unlearn is the rule that using pointers is faster than
using array indexing. Very often it's the other way around
now.

Here's a revised hex_image that uses indexing rather than direct
pointer manipulation.


#define NIBBLES_PER_CHAR ((CHAR_BIT+3)/4)

char *
hex_image( void *addr, size_t len ){
char (*out)[NIBBLES_PER_CHAR] = malloc( NIBBLES_PER_CHAR*len + 1 );
unsigned char *in = addr;
size_t i;

if (out == NULL) return NULL;

for (i = 0; i < len; i ++) {
sprintf( out, "%0*x", NIBBLES_PER_CHAR, in );
}
return out[0];
}


(The name of the macro was changed because I expect ..._CHAR is
less likely to cause confusion than ..._BYTE.)
 
K

Keith Thompson

Tim Rentsch said:
Here's a function that returns a hexadecimal image of any object,
given its address and its size in bytes. The caller needs to free()
the result after using it.
[snip]

As compiler technology has gotten better, one of the rules I've
had to unlearn is the rule that using pointers is faster than
using array indexing. Very often it's the other way around
now.

Here's a revised hex_image that uses indexing rather than direct
pointer manipulation.


#define NIBBLES_PER_CHAR ((CHAR_BIT+3)/4)

char *
hex_image( void *addr, size_t len ){
char (*out)[NIBBLES_PER_CHAR] = malloc( NIBBLES_PER_CHAR*len + 1 );
unsigned char *in = addr;
size_t i;

if (out == NULL) return NULL;

for (i = 0; i < len; i ++) {
sprintf( out, "%0*x", NIBBLES_PER_CHAR, in );
}
return out[0];
}


(The name of the macro was changed because I expect ..._CHAR is
less likely to cause confusion than ..._BYTE.)


Hmm. Let's assume for simplicity that CHAR_BIT==8. You've declared
out as a pointer to an array of 2 chars. That's perfectly legal, of
course, but there's enough confusion between arrays and pointers that
I'm still more comfortable with pointers to chars than with pointers
to arrays.

The space you allocate with malloc() has a size that is not a multiple
of the size of the pointed-to type.

In the sprintf() call, out points to an array of 2 chars, but you
write 3 bytes to it. It's hard to see how this could fail, but it
worries me.

I think the real lesson to be learned is that it seldom matters
whether using pointers or indices is faster; the compiler will often
be able to generate optimal code for either. I suspect the real
bottleneck in my original version (and in yours) is the call to
sprintf().
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Here's a function that returns a hexadecimal image of any object,
given its address and its size in bytes. The caller needs to free()
the result after using it.
[snip]

As compiler technology has gotten better, one of the rules I've
had to unlearn is the rule that using pointers is faster than
using array indexing. Very often it's the other way around
now.

Here's a revised hex_image that uses indexing rather than direct
pointer manipulation.


#define NIBBLES_PER_CHAR ((CHAR_BIT+3)/4)

char *
hex_image( void *addr, size_t len ){
char (*out)[NIBBLES_PER_CHAR] = malloc( NIBBLES_PER_CHAR*len + 1 );
unsigned char *in = addr;
size_t i;

if (out == NULL) return NULL;

for (i = 0; i < len; i ++) {
sprintf( out, "%0*x", NIBBLES_PER_CHAR, in );
}
return out[0];
}


(The name of the macro was changed because I expect ..._CHAR is
less likely to cause confusion than ..._BYTE.)


Hmm. Let's assume for simplicity that CHAR_BIT==8. You've declared
out as a pointer to an array of 2 chars. That's perfectly legal, of
course, but there's enough confusion between arrays and pointers that
I'm still more comfortable with pointers to chars than with pointers
to arrays.


I'll grant you that most developers use pointers to arrays only
rarely, if at all. To some extent though that's self-reinforcing
behavior - people don't use them because they aren't used to
them, and they aren't used to them because they don't use them.
The code above wasn't natural for me when I wrote it; but I
think it's good to stretch a bit at times to get out of the
local ruts that seem only too easy to fall into.

The space you allocate with malloc() has a size that is not a multiple
of the size of the pointed-to type.

That's true. It's for the final string termination character, of
course - there's a sense in which the array is being filled with
elements of NIBBLES_PER_CHAR characters each, and then a final
zero character added at the end to make it a string. Now that you
mention it, it might have been better to write that malloc() call
as

char (*out)[NIBBLES_PER_CHAR] = malloc( len * sizeof *out + 1 );

which may show a little more clearly why the size is chosen as it
is.

In the sprintf() call, out points to an array of 2 chars, but you
write 3 bytes to it. It's hard to see how this could fail, but it
worries me.


I understand the worry. I've looked at language in both the
standard and the Rationale document; I think I can make a pretty
strong case that it's required to succeed, but I'm sure there are
those who would argue against that.

I think the real lesson to be learned is that it seldom matters
whether using pointers or indices is faster; the compiler will often
be able to generate optimal code for either. I suspect the real
bottleneck in my original version (and in yours) is the call to
sprintf().

My experience (of the last few years, in case that matters) has
been that the compiler usually does a little better generating
code when indexing is used. That's contrary to "conventional
wisdom" so I thought it might be good to report that. The usage
of the variable 'out' is a little bit funny, I might even say
unclear; but I think it does show a little more directly how the
output is being produced in blocks of characters corresponding to
each input character. Don't get me wrong, I don't think either
version is better than the other -- each has its plusses and
minuses.[*] It just occurred to me that this function might be a
good example to illustrate the array-ful nature of the processing
being done, and how that might be expressed.


[*] In comp.lang.c, we might say each has its pluspluses and
minusminuses. :)
 
L

Lawrence Kirby

On Sat, 18 Jun 2005 16:38:38 -0700, Tim Rentsch wrote:

....
I'll grant you that most developers use pointers to arrays only
rarely, if at all. To some extent though that's self-reinforcing
behavior - people don't use them because they aren't used to
them, and they aren't used to them because they don't use them.

Pointers to arrays are a natural adjunct to arrays of array. IMO the real
issue is that people don't use arrays of arrays much. And even when you do
you don't alwayes need to use (as an explicit pointer object) a pointer to
an array. They seem to come up most when trying to pass an array of arrays
to another function, but your example of allocating an array of arrays
dynamically is good too.


The code above
wasn't natural for me when I wrote it; but I think it's
good to stretch a bit at times to get out of the local ruts that seem
only too easy to fall into.

The space you allocate with malloc() has a size that is not a multiple
of the size of the pointed-to type.

That's true. It's for the final string termination character, of course
- there's a sense in which the array is being filled with elements of
NIBBLES_PER_CHAR characters each, and then a final zero character added
at the end to make it a string. Now that you mention it, it might have
been better to write that malloc() call as

char (*out)[NIBBLES_PER_CHAR] = malloc( len * sizeof *out + 1 );

which may show a little more clearly why the size is chosen as it is.

In the sprintf() call, out points to an array of 2 chars, but you
write 3 bytes to it. It's hard to see how this could fail, but it
worries me.


I understand the worry. I've looked at language in both the standard
and the Rationale document; I think I can make a pretty strong case
that it's required to succeed, but I'm sure there are those who would
argue against that.


Yes, you're writing outside the bounds of the array. The array in
question is out which is (in the specified conditions) a 2 element
array. What you are passing as the first argument to sprintf() is a
pointer to the first element of this 2 element array. When the call to
sprintf() writes to out[2] it invokes undefined behaviour.

Lawrence
 
T

Tim Rentsch

Lawrence Kirby said:
On Sat, 18 Jun 2005 16:38:38 -0700, Tim Rentsch wrote:
[restored context]

char (*out)[NIBBLES_PER_CHAR] = malloc( NIBBLES_PER_CHAR*len + 1 );
...
for (i = 0; i < len; i ++) {
sprintf( out, "%0*x", NIBBLES_PER_CHAR, in );
}

[end restored context]
In the sprintf() call, out points to an array of 2 chars, but you
write 3 bytes to it. It's hard to see how this could fail, but it
worries me.


I understand the worry. I've looked at language in both the standard
and the Rationale document; I think I can make a pretty strong case
that it's required to succeed, but I'm sure there are those who would
argue against that.


Yes, you're writing outside the bounds of the array. The array in
question is out which is (in the specified conditions) a 2 element
array. What you are passing as the first argument to sprintf() is a
pointer to the first element of this 2 element array. When the call to
sprintf() writes to out[2] it invokes undefined behaviour.


If you look at the actual language I think you'll find
that it's not as simple as that. So I need to ask you
to cite "chapter and verse", as they say. I've looked
at the actual language quite carefully.
 
K

Keith Thompson

Tim Rentsch said:
I'll grant you that most developers use pointers to arrays only
rarely, if at all. To some extent though that's self-reinforcing
behavior - people don't use them because they aren't used to
them, and they aren't used to them because they don't use them.
The code above wasn't natural for me when I wrote it; but I
think it's good to stretch a bit at times to get out of the
local ruts that seem only too easy to fall into.

Agreed.

I'd also speculate that pointers to arrays are used accidentally
nearly as often as they're used deliberately (by programmers who don't
quite understand the interactions between arrays and pointers). Such
code often works by accident if a pointer-to-char and a
pointer-to-array-of-char happen to have the same representation.

If I see code that uses pointers to arrays, I need to carefully trace
the logic before I can be sure that it's actually correct.

This isn't a criticism of your code, but unusual constructs usually
call for a comment explaining what's really going on.

[...]
I understand the worry. I've looked at language in both the
standard and the Rationale document; I think I can make a pretty
strong case that it's required to succeed, but I'm sure there are
those who would argue against that.

Which I would say is a good argument to avoid using it.
 
T

Tim Rentsch

Keith Thompson said:
Agreed.

I'd also speculate that pointers to arrays are used accidentally
nearly as often as they're used deliberately (by programmers who don't
quite understand the interactions between arrays and pointers). Such
code often works by accident if a pointer-to-char and a
pointer-to-array-of-char happen to have the same representation.

Interesting idea. Have you ever actually seen it? I'd expect
that normally the distinction would be caught by during type
checking.

If I see code that uses pointers to arrays, I need to carefully trace
the logic before I can be sure that it's actually correct.

This isn't a criticism of your code, but unusual constructs usually
call for a comment explaining what's really going on.

Yes. Pointer-to-arrays still usually fall in that category. It
would be nice if more people got comfortable with some basic
patterns for using pointer-to-arrays so that were less true.

[...]
I understand the worry. I've looked at language in both the
standard and the Rationale document; I think I can make a pretty
strong case that it's required to succeed, but I'm sure there are
those who would argue against that.

Which I would say is a good argument to avoid using it.

Perhaps. It depends on who are offering the arguments, and what
the arguments are.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top