473,403 Members | 2,366 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,403 software developers and data experts.

printing a pointer

Hi,

To print the pointer using printf(), we convert it to (void *) .
printf("%p",(void *)ptr);
My question is how printf() determine which type of pointer is passed
to it and
prints its value accordingly ? I have this doubt as different
pointers may have
different representation and different size. So, how does printf
determine
which type of pointer it has to print and what is the representation
and size
of that pointer ?

Also, why do we need to cast it to (void *) at all ?

thanks for any help ...

Nov 24 '06 #1
9 2991
ju**********@yahoo.co.in wrote:
Hi,

To print the pointer using printf(), we convert it to (void *) .
printf("%p",(void *)ptr);
My question is how printf() determine which type of pointer is passed
to it and
prints its value accordingly ?
It doesn't. It assumes you pass it a void *, and if you don't, things
may break and you get to keep the pieces.
[...]
Also, why do we need to cast it to (void *) at all ?
So that printf() doesn't have to determine which type of pointer is
passed to it.

Nov 24 '06 #2
"ju**********@yahoo.co.in" wrote:
>
To print the pointer using printf(), we convert it to (void *) .
printf("%p",(void *)ptr);
My question is how printf() determine which type of pointer is
passed to it and prints its value accordingly ? I have this doubt
as different pointers may have different representation and
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
different size. So, how does printf determine which type of
^^^^^^^^^^^^^^
pointer it has to print and what is the representation and size
of that pointer ?

Also, why do we need to cast it to (void *) at all ?
Didn't you just answer your own question? %p expects a void*.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Nov 24 '06 #3

Harald van Dijk wrote:
>
[...]
Also, why do we need to cast it to (void *) at all ?

So that printf() doesn't have to determine which type of pointer is
passed to it.
But, then it may print which was not not desired. I mean to say
that I wanted to print a (char *) but end up printing a (void *)
conversion of (char *).

Why not pass the pointer as it is (without any conversion to void *)
and let printf() print the actual pointer ?

Nov 25 '06 #4
[regarding printf and the %p directive]
>> Also, why do we need to cast [the argument] to (void *) at all ?
>Harald van Dijk wrote:
>So that printf() doesn't have to determine which type of pointer is
passed to it.
In article <11**********************@j72g2000cwa.googlegroups .com>
ju**********@yahoo.co.in <ju**********@yahoo.co.inwrote:
>But, then it may print which was not not desired. I mean to say
that I wanted to print a (char *) but end up printing a (void *)
conversion of (char *).
This is indeed the case. It is similar to a printf-like function
(perhaps we could call it "dprintf") that has no integer conversion
directives, so that you have to convert any "int"s to "double" and
use %f, probably with .0:

int i, j;
...
dprintf("i = %.0f, j = %.0f\n", (double)i, (double)j);

This makes dprintf() simpler than printf() -- because dprintf() has
no %i and %d conversions, only %f (and maybe others) -- at the cost
of making the calls more complicated.
>Why not pass the pointer as it is (without any conversion to void *)
and let printf() print the actual pointer ?
In order to do that, we would have to modify the printf() engine to
be able to tell it what kind of pointer we gave it. For instance,
suppose we wrote a pprintf() function that, instead of one "%p"
directive, had "%<char>p" for "pointer to char", "%<int>p" for
"pointer to int", "%<double>p" for "pointer to double", and so on:

int *ip;
char *cp;
struct foo *foop;
...
/*
* With "ordinary" printf, this would be:
* printf("ip = %p, cp = %p, fooo=%p,
* (void *)ip, (void *)cp, (void *)foop);
* but we have our proposed pprintf() function, so:
*/
pprintf("ip = %<int>p, cp = %<char>p, foop=%<struct foo>p\n",
ip, cp, foop);

The calls are simplified, compared to using printf(), because we
can now omit the casts. But how would you write the pprintf() code?
Somewhere inside pprintf() we must handle %<...>p directives:

/* ... handling % ... */
case '<':
... collect up type name to '>' and expect subsequent "p" */
...
case 'p':
if (we have a saved type name)
expected_type = decode_type(saved_type);
else
expected_type = VOIDSTAR;
switch (expected_type) {
case INTSTAR:
... code to handle "int *" ...
break;
case CHARSTAR:
... code to handle "char *" ...
break;
case VOIDSTAR:
... code to handle "void *" ...
break;
case STRUCTFOOSTAR:
... code to handle "struct foo *" ...
break;
... more cases as needed ...
}
break;
...

How will you write the code to decode and handle these various
cases? (Feel free to change the syntax -- perhaps instead of
the complicated %<name>p format, you would just use %C for char*,
%V for void*, %I for int*, and so on. How many type-names do
you need? What letter(s) will you use for, e.g., "char *(*)[5]?)

Was this a good tradeoff, moving complexity into this new pprintf()
to avoid casts calls to printf()?
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 25 '06 #5
ju**********@yahoo.co.in wrote:
Harald van Dijk wrote:
[...]
Also, why do we need to cast it to (void *) at all ?
So that printf() doesn't have to determine which type of pointer is
passed to it.

But, then it may print which was not not desired. I mean to say
that I wanted to print a (char *) but end up printing a (void *)
conversion of (char *).
Well, void * and char * happen to have exactly the same representation,
but since char * is a special case, let's ignore that.

What exactly do you want to print? The bytes that make up a char *, or
the address it points to (along with any additional information that
may or may not be stored in the pointer)? If the former, you can access
your pointer as an array of unsigned char, and print each element in
whatever format you choose. If the latter, after converting it to void
*, it still points to exactly the same address, and although it's not
guaranteed, I personally see no reason to assume any additional
information would be changed.
Why not pass the pointer as it is (without any conversion to void *)
and let printf() print the actual pointer ?
You answered that already in your original message.

Nov 25 '06 #6


On Nov 25, 11:49 am, Chris Torek <nos...@torek.netwrote:
junky_fel...@yahoo.co.in <junky_fel...@yahoo.co.inwrote:
But, then it may print which was not not desired. I mean to say
that I wanted to print a (char *) but end up printing a (void *)
conversion of (char *).This is indeed the case. It is similar to a printf-like function
(perhaps we could call it "dprintf") that has no integer conversion
directives, so that you have to convert any "int"s to "double" and
use %f, probably with .0:

int i, j;
...
dprintf("i = %.0f, j = %.0f\n", (double)i, (double)j);

This makes dprintf() simpler than printf() -- because dprintf() has
no %i and %d conversions, only %f (and maybe others) -- at the cost
of making the calls more complicated.
Why not pass the pointer as it is (without any conversion to void *)
and let printf() print the actual pointer ?In order to do that, we would have to modify the printf() engine to
be able to tell it what kind of pointer we gave it. For instance,
suppose we wrote a pprintf() function that, instead of one "%p"
directive, had "%<char>p" for "pointer to char", "%<int>p" for
"pointer to int", "%<double>p" for "pointer to double", and so on:

int *ip;
char *cp;
struct foo *foop;
...
/*
* With "ordinary" printf, this would be:
* printf("ip = %p, cp = %p, fooo=%p,
* (void *)ip, (void *)cp, (void *)foop);
* but we have our proposed pprintf() function, so:
*/
pprintf("ip = %<int>p, cp = %<char>p, foop=%<struct foo>p\n",
ip, cp, foop);

The calls are simplified, compared to using printf(), because we
can now omit the casts. But how would you write the pprintf() code?
Somewhere inside pprintf() we must handle %<...>p directives:

/* ... handling % ... */
case '<':
... collect up type name to '>' and expect subsequent "p" */
...
case 'p':
if (we have a saved type name)
expected_type = decode_type(saved_type);
else
expected_type = VOIDSTAR;
switch (expected_type) {
case INTSTAR:
... code to handle "int *" ...
break;
case CHARSTAR:
... code to handle "char *" ...
break;
case VOIDSTAR:
... code to handle "void *" ...
break;
case STRUCTFOOSTAR:
... code to handle "struct foo *" ...
break;
... more cases as needed ...
}
break;
...

How will you write the code to decode and handle these various
cases? (Feel free to change the syntax -- perhaps instead of
the complicated %<name>p format, you would just use %C for char*,
%V for void*, %I for int*, and so on. How many type-names do
you need? What letter(s) will you use for, e.g., "char *(*)[5]?)

Was this a good tradeoff, moving complexity into this new pprintf()
to avoid casts calls to printf()?
thanks a lot Chris and Herald Van Dijk for your help. Now, I know the
reason for converting a pointer to (void *) while passing it to
printf().

I think, the main problem with the newbies like me is that we haven't
worked on vast number of different processor architectures. The
architectures that I have worked on have same size and same
representation for all types of pointers and they can be converted
to int/long without losing any information. The pointers are plain
integers on these architectures (m68k, powerpc, ARM). The people
like me are not to appreciate the various constraints that are imposed
by C standard (like pointer conversion to integer or to pointer of some
other type).

Can you please give an example (or point out some links)
of some architectures where different pointers have different size
and representation, where the pointers are not plain integers ?
On such architecures, what happens when a pointer is converted
to an integer or viceversa ? I would be highly grateful if you can
give some examples (or point to some links).

There are lots of books on C that are available in the market. But
none of them explain the things by giving examples of various
processor architecture, so the newbies can undertand the importance
of these constraints. Are you or anybody else aware of any such
book ?

Nov 25 '06 #7
"ju**********@yahoo.co.in" wrote:
>
.... snip ...
>
Can you please give an example (or point out some links)
of some architectures where different pointers have different size
and representation, where the pointers are not plain integers ?
On such architecures, what happens when a pointer is converted
to an integer or viceversa ? I would be highly grateful if you can
give some examples (or point to some links).
You need go no further than MsDos, intermixing small and large
models.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

Nov 25 '06 #8
In article <11*********************@j72g2000cwa.googlegroups. com>
ju**********@yahoo.co.in <ju**********@yahoo.co.inwrote:
>I think, the main problem with the newbies like me is that we haven't
worked on vast number of different processor architectures. The
architectures that I have worked on have same size and same
representation for all types of pointers and they can be converted
to int/long without losing any information. ...
>Can you please give an example (or point out some links)
of some architectures where different pointers have different size
and representation, where the pointers are not plain integers ?
They are not as common today as they once were. On the other
hand, they are more common today than they were before. :-)
(That is, they were common, then they became rare, and now they
less-rare than the intermediate time.)

In the old days of "mainframes" and "minicomputers", there were
a lot of machines that were "word-addressed" (rather than "byte-
addressed", as most of today's machines are). That is, while
addresses were still integral units, "address 0" might contain
the machine's first 36-bit word, then "addresss 1" contains the
second group of 36 bits, and so on.

This was in fact the case on Univac 11xx-series architectures. To
make a C compiler work on such a machine, you have two options:

- make "char" 36 bits, or
- make "char" 9 bits, and pack 4 "char"s into a machine word.

For many reasons, the latter was usually (maybe always) chosen.
The underlying hardware was, peculiarly, "semi-capable" of addressing
a 9-bit "quarterword" within a word: if you knew *which* quarter
word to select at compile time, you could do that; but if you had
to pick one out at runtime, you could not.

(I never got into the details of the few C compilers available for
11xx machines, so this is about all I can say about those.)

On some Cray machines, the same problem led to putting the byte
offset for the (64-bit) machine word address in some of the high
order bits of a "char *" pointer, so if you had some machine word
at address 0x1234, and set a "char *" to point to it:

char *cp = (char *)0x1234;
printf("cp = %16.16lx; cp + 1 = %16.16lx\n", (long)cp, (long)(cp + 1));

the values printed would be 0000000000001234 and 0001000000001234
respectively. The high bits count 0 to 7, then the low bits
increment.

On some models of the PR1ME, the same problem occurred, but all 32
bits of the 32-bit address of the 16-bit-wide machine word were in
use, so "char *" became 48 bits wide, with the extra 16 bits holding
a single bit specifying which byte of the 16-bit word to use.

On the Data General Eclipse (MV/10000 series), which evolved out
of the Nova, the hardware could address individual 8-bit bytes
directly. However, there were *two* native pointer formats, one
for 8-bit bytes, and one for 16-bit words. The C compiler used
both: "char *" used 8-bit-byte pointers, and "short *" and other
larger data types (int and long) used 16-bit-word pointers. The
difference between byte and word pointer was that the word pointer
had one extra bit at the top, the "indirect" bit, while the byte
pointer had one extra bit at the bottom, the "byte offset". To
convert a byte pointer to a word pointer, one did a right-shift,
discarding the byte-offset and introducing a zero-bit for the
"indirect" bit; to convert a word pointer to a byte pointer, one
did a left-shift, discarding the "indirect" bit and introducing
a zero bit for the byte offset.

No doubt there were others; those are the only ones I know off-hand.

We also have the IBM AS/400, even today; but its main "odd" feature
for pointers is that function pointers are much wider than data
pointers. (Data pointers seem to be 64 bits, so should fit in a
"long long".)

Today, we are seeing a resurgence of the "dual mode" systems that
were common in the 80286 days, except instead of "16-bit pointer"
and "32-bit pointer", we now have "32-bit pointer" and "64-bit
pointer". In some cases, the "mode" (32 or 64 bit addressing) of
the machine is per-process, but in at least one, it is per-stack-
frame: on the V9 sparc, one indicates that the current stack frame
is operating in 64-bit mode by offseting the stack pointer by 2047:
a %sp whose numerical value is congruent to zero mod 8 indicates
a 32-bit frame, while one whose numerical value is congruent to 7
mod 8 indicates a 64-bit frame. (Thus, it should be possible to
call 32-bit libraries from 64-bit programs, and vice versa, provided
the 32-bit code is only dealing with addresses in the lowest four
gigabytes.)
>On such architecures, what happens when a pointer is converted
to an integer or viceversa?
This depends on the machine. If there is an integral type wide
enough, it generally "just works". The conversion is usually
entirely straightforward: for instance, on the Eclipse, converting
a pointer -- whether byte or word -- to a 32-bit integer leaves
the bit pattern unchanged. This allows you to inspect or set the
byte-offset or indirect bit, whichever the pointer has. Note that
this means the ring and segment numbers are shifted one bit left
or right respectively (pointers on the Eclipse were split into
"ring", "segment", and "base address", along with the indirect or
byte-offset bit at the top or bottom).

Probably the PR1ME simply could not convert "char *" to integral.

On the 80286, you had to use a "long" to store a 32-bit pointer.
On some of today's 32-and/or-64-bit machines, you may have to use
a "long long" to store a pointer. (C compiler writers can choose
from various models: "ILP32" means int, long, and pointers are all
32 bits; "I32LP64" means "int is 32 bits, long and pointers are 64
bits"; and "IL32P64" means "int and long are 32 bits, pointers are
64 bits". While I32LP64 is clearly much more elegant, some compiler
writers have chosen IL32P64 to accomodate poorly-written C code
that assumes "int" and "long" are identical. Of course, this breaks
C code that assumes "long" and "pointer" are identical -- but so
it goes. Note that only ILP32 keeps broken code "working"; but it
gives up the advantage of the 64-bit address space!)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 25 '06 #9
ju**********@yahoo.co.in wrote:
Can you please give an example (or point out some links)
of some architectures where different pointers have different size
and representation, where the pointers are not plain integers ?
On such architecures, what happens when a pointer is converted
to an integer or viceversa ? I would be highly grateful if you can
give some examples (or point to some links).
The first discrete Harvard architecture signal processing system I
worked on used separate (64 bit) code and (16 bit) data spaces. We had
different sized data and code pointer types. My guess is that there are
still DSPs around today that follow this pattern.

--
Ian Collins.
Nov 25 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Steven T. Hatton | last post by:
I'm trying to write a program like hexel. I guess I could fish out the source for hexel and look at that, but for now I'm trying to figure out how I can do with with std::stringstream and...
9
by: weaselboy1976 | last post by:
Hello How can I print a pointer's value directly (without assigning the value to another variable)? For example: #include <stdio.h> int main() { int *zp;
42
by: junky_fellow | last post by:
Consider an implementation that doesn't use all bits 0 to represent a NULL pointer. Let the NULL pointer is represented by 0x12345678. On such an implementation, if the value of NULL pointer is...
5
by: Tom | last post by:
I am converting an old application that was printing directly to a specialized printer device (i.e. a special label printer). It was doing this by opening a file with the file path of 'LPT1:' and...
2
by: Samuel Shulman | last post by:
Hi I have written an entire module in .NET printing using a PrintDocument but now the users complain that they want something like .lay files that will allow them to change the layout of the...
57
by: Robert Seacord | last post by:
i am trying to print the address of a function without getting a compiler warning (i am compiling with gcc with alot of flags). if i try this: printf("%p", f); i get: warning: format %p...
6
by: dissectcode | last post by:
I have looked at a ton pages relevant to printing pointers and I still need clarity. I read here: http://bytes.com/forum/thread219302.html , that to print with %d you "need to cast the pointer to...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.