Address of array && address of pointer to array

J

James Kuyper

How to print the address of a pointer is implementation dependant,
based on how to represent the pointer. Now I can understand two
pointers point to the same memory location may print differently.

But is it possible that two different pointers that point two
different address print the same.

No, because the same character strings that are printed out when you use
printf("%p", ...) must be readable by scanf("%p", ...), and the result
of the read must be a pointer that compares equal to the original. If
two pointers that pointed at different locations caused the same string
to be printed out, then when scanned back in, the would necessarily
compare equal not only to their originals, but also to each other, since
the printed strings provide no way to distinguish them. Pointers to
different locations in memory are not allowed to compare equal, so they
must print out different character strings.

Equal pointers can print differently (though it is unlikely that they
would do so); unequal pointers MUST print differently.
 
N

Nobody

No, it isn't. The string printed by printf with "%p" must be readable
by scanf with "%p", and the result from scanf must compare equal to the
original pointer.

Ah. I actually checked the spec regarding printf("%p"), which doesn't say
anything useful:

p The argument shall be a pointer to void. The value
of the pointer is converted to a sequence of
printable characters, in an implementation-defined
manner.

It didn't occur to me to check scanf(), which says:

p Matches an implementation-defined set of sequences,
which should be the same as the set of sequences
that may be produced by the %p conversion of the
fprintf function. The corresponding argument shall
be a pointer to a pointer to void. The
interpretation of the input item is implementation-
defined. If the input item is a value converted
earlier during the same program execution, the
pointer that results shall compare equal to that
value; otherwise the behavior of the %p conversion
is undefined.

Which suggests that the answer to the question:
Can we say that, two pointers must be equal if they are printed the same.

should be "yes" (subject to the proviso that comparing the pointers for
equality is actually legal).

However: I suggest that it would be legal for the implementation to print
all pointers as "?" if it can detect that the *scanf() functions aren't
used by the program.
 
B

Ben Bacarisse

It's helpful to snip sig blocks, even short ones. I try to cut down
what I quote to a bare minimum so that posts a re short but still have
what is needed to establish the context.
Err, I seems that I am just a novice and I don't fully understand the
pointer. Why should a pointer have to an object that has a specific
type, even,(void). Every code and variable and anything else just
store in the memory. Does the pointer with the specific type to point
to locate how much memory space to charge?

I think you are confusing pointers and addresses. An address is a
machine concept and a pointer is a C language concept. They are, of
course, closely related, but a pointer includes a type and that
determines what you can and can't do. For example,

int a = 42;
int *ip = &a;
void *vp = ip;

both ip and vp refer to the same place -- in some sense that represent
the same machine address; but:

(a) You can write *ip but you can't write *vp.
(b) You can write char *cp = vp; but you can't write char *cp = ip;
(note that there are no casts here).
(c) ip + 1 is a perfectly valid pointer but vp + 1 is not permitted.
(d) Neither *(ip + 1) nor *(vp + 1) is permitted though for different
reasons.
(e) ip + 2 is *not* a valid pointer. Neither is ip - 1.

These restrictions come from the C language. If you think of pointers
as machine addresses on some system or other the restrictions probably
don't make much sense, but they are there because pointers offer an
abstract view of addresses that must work on all kinds of hardware.

<snip>
I found it hard to follow the rest. I'm sorry about that.
 
N

Nobody

I am not fully understand your meaning of "function pointers are
bigger than void *". I know it's not the size of the pointer.

No, he means the size of the pointer itself.

Pointers don't have to all have the same size. The most common
counter-example is 8086 memory models.

The "medium" model has multiple code segements but a single data segment,
so a function pointer is 32 bits (segment + offset) while a data pointer
(including "void*") is 16 bits (offset only).

The "compact" model is the other way around (a single code segment but
multiple data segments).

A less common counter-example is word-addressed architectures, where a
pointer to a type smaller than a word must contain both the address of the
word and an offset within the word. Pointers to types as large as or
larger than a word don't require the offset.
 
J

James Kuyper

Pete is right, and I apologize for not noticing that problem and
commenting on it in my own message.

....
Err, I seems that I am just a novice and I don't fully understand the
pointer. Why should a pointer have to an object that has a specific
type, even,(void). Every code and variable and anything else just
store in the memory. Does the pointer with the specific type to point
to locate how much memory space to charge?

A fully conforming implementation of C could store type information
inside of a pointer, but most do not. For a typical C implementation,
the type that a pointer points at is something that is implicit in the
machine code generated by your program, rather than stored in the
pointer itself, so that is not the issue.

The most common context where function pointers are incompatible with
void* pointers is machines where executable code resides in a different
memory space from the data. I've worked on machines where the compilers
could be put into a mode where data addresses were only 16 bits, while
function addresses had 32 bits. I wouldn't be surprised (and none of my
programs would fail) if, on a more modern system, data addresses had 32
bits, while function addresses had 64. That's because I never write code
that tries to stuff a function pointer into a void* pointer - there
might not be enough room for it to do so.
For example, a pointer points to type int means that 4 bytes of memory
is in the charge of the pointer, and a pointer points to type char
means that 1 byte of memory is in the charge of the pointer. In this
way, when we dereference a pointer that points to type int, we can get
a 4 byte integer, and when we dereference a pointer to char, we can
get one byte character. Is that right? And I wrote a testing program,
the snippet is as below:

int a = 48; // 48 represents character '0' in ASCII

It's better to write

int a = '0';

This has the minor advantage of making your code portable to systems
that don't use ASCII. That's only a minor advantage, despite the fact
that ASCII is becoming less common, because most of the popular
alternatives to ASCII (such as UTF8) use the same values as ASCII for
the basic C character set.

The major advantage of using '0' rather than 48 is that it makes it very
much clearer what you are trying to do.
int *b = &a;
char *c = (char *)b;

This is legal; it leaves c pointing at the first byte of 'a'. That byte
might or might not have a value of 48, depending upon whether int is
bigendian or little-endian.
printf("%c\n", c); //2

The variable 'c' is a pointer; the "%c" format specifier requires that
the corresponding argument have a type that promotes to 'int', and
"char*" is NOT such a type. The behavior of your program is undefined.
The printf statement prints the character '0'.

Because the behavior is undefined, it's possible that this is what your
program actually printed out, but I think that is extremely unlikely. I
suspect that the code which you actually executed may have looked like this:

printf("%c\n", *c);
If my assumption is correct, then may be I can guess why casting a
pointer to function to void* is undefined. The pointer points to the
starting address of the function, without knowing the whole length of
the function, so the pointer doesn't know how many bytes could the
pointer in charge of, right?

No, not really. A function pointer doesn't need to know how long the
function is. It typically encodes a location in memory at which the
first instruction implementing the function is located. Calling the
function involves a jump to that location, after which instructions are
executed in order, one after another, until sooner or later an
instruction is executed that cause either the function to return or the
program to exit.
 
S

Stanley Rice

You "know" incorrectly. Function pointers can have a size that is
different from the size of void*, and there have been many systems where
this is indeed the case.

But I try to print sizeof(void *) and sizeof(ptr2fun), supposing that
ptr2fun
is a function pointer. It generate the same result, both are 4. So is
your
meaning that in some special cases, the size of function pointer and
the
pointer to void * is different? And could you explain to me when it
occurs?
 
J

James Kuyper

On 09/16/2011 05:09 AM, Keith Thompson wrote:
....
A function pointer isn't necessarily the memory address of the start
of the function. On most systems you're likely to use, it probably
will be, but the standard doesn't guarantee it. For example, it
could be an index into a table of all the functions in your program.
Or it could contain additional system-specific information. (As I
recall, function pointers on the IBM AS/400 are something like
16 bytes, though it's very likely I've got the details wrong.)

Another alternative that I've seen, which you didn't mention, is that
the instruction in the program which should be executed first might be
different from the instruction in the program with the lowest memory
address. At some point during the function call the function might jump
back to a position lower in memory than the initial instruction. I don't
know why the compiler where I saw this happen organized the code that
way, but I gather that this particular compiler did so routinely; it
wasn't just a bizarre consequence of a particular optimization strategy.
 
J

James Kuyper

But I try to print sizeof(void *) and sizeof(ptr2fun), supposing that
ptr2fun
is a function pointer. It generate the same result, both are 4. So is
your
meaning that in some special cases, the size of function pointer and
the
pointer to void * is different? And could you explain to me when it
occurs?

The size of the void* and the size of a given function pointer type are
both implementation-specific, and there's no requirement that they be
the same. On a different implementation, they might be different, and
either one might be larger than the other.

There's only a few cases where the standard imposes any size
requirements. Note that, in C, a byte contains CHAR_BIT bits, and
CHAR_BIT is allowed to be greater than 8. (5.2.4.2.1p1).

The minimum required range of the basic integer type implies a minimum
number of bits needed to store each type (5.2.4.2.1p1):
short, int: 16 bits
long: 32 bits
long long: 64 bits

char and signed char have the same size. (6.2.5p5)

For every signed integer type, the corresponding unsigned integer type
must have the same size. (6.2.5p6)

float _Complex is required to have the same size as float[2]; similarly
for double and long double. (6.2.5p13)

For any given type T:
const T, volatile T, and const volatile T are all required to have the
same size. (6.2.5p26)

For any given pair of compatible types T and U (including T==U as a
special case),
T*, const T*, volatile T*, and const volatile T*, U*, const U*, volatile
U*, and const volatile U* are all required to have the same size. (6.2.5p27)

char*, signed char*, unsigned char*, and void* are all required to have
the same size. (6.2.5p27)

All pointers to structure types have the same size. (6.2.5p27)

All pointers to union types have the same size. (6.2.5p27)

Pointers to other types need NOT have the same size (6.2.5p27)

char, signed char, and unsigned char all have a size of 1 byte (6.5.3.4p3).

The exact-width types, intN_t, take up exactly N bits of memory.
(7.18.1.1p2)
The minimum-width and fastest minimum-width types, int_leastN_t
(7.18.1.2p2) and int_fastN_t (7.18.1.3p2), take up at least N bits of
memory, but possibly more.

The minimum required ranges of certain other types imply a minimum
number of bits (7.18.2.4p1):
sig_atomic_t, wchar_t: 8 bits
inptr_t, uintptr_t, ptrdiff_t, size_t, wint_t: 16 bits

float _Imaginary is required to have same size as float; similarly for
double and long double. (Annex Gp4)

For any types not listed above, you should avoid making any assumptions
about their sizes.
 
B

Bart van Ingen Schenau

Stanley said:
Err, I seems that I am just a novice and I don't fully understand
the pointer. Why should a pointer have to an object that has a
specific type, even,(void). Every code and variable and anything else
just store in the memory. Does the pointer with the specific type to
point to locate how much memory space to charge?

It might be true for the computer that you are sitting at that everything is
stored in a single big pool of memory, but C is defined to be flexible
enough that it also can deal with really weird systems.
It is, for example, possible to use C on a system with these
characteristics:
- code and data are stored in physically different areas of memory.
- code memory has 2^48 locations where functions can be located. (^ used in
the meaning of 'power of')
- data memory has 2^16 16-bit wide cells.
- the C compiler provides byte (octet) access through emulation.
On this system, you would have:
* CHAR_BITS == 8
* sizeof(char) == 1
* sizeof(short) == sizeof(int) == 2
* sizeof(long) == 4
* sizeof(void*) == sizeof(char*) == 4
* sizeof(int*) == 2
* sizeof(void (*)() /* function pointer */) == 6

As you can see, the size of the pointers themselves is not always the same
and depends on the type of data that the pointer points at.
In this case, void* and char* need to be larger to store the additional
information which portion of a memory-cell the pointer refers to.
For example, a pointer points to type int means that 4 bytes of
memory is in the charge of the pointer, and a pointer points to type
char means that 1 byte of memory is in the charge of the pointer. In
this way, when we dereference a pointer that points to type int,
we can get a 4 byte integer, and when we dereference a pointer
to char, we can get one byte character. Is that right? And I wrote
a testing program, the snippet is as below:

int a = 48; // 48 represents character '0' in ASCII
int *b = &a;
char *c = (char *)b;
printf("%c\n", c); //2

The printf statement prints the character '0'. I guess the reason is
that,according to the little-endian priciple, integer 48 stores in the
side of least significant bit, but its memory address is lowest.

This may happen to be true for your computer, but it is not universally
true. It is equally well possible that the processor uses big-endian storage
and the integer 48 is stored in the higest byte of the memory used by the
variable a.
In that case, the printf would have resulted in the character '\0' (which is
typically invisible).

So I guess the use of pointer pointed type is to determine how
many byte could this pointer in charge from the least significant byte.
But I don't know whether I'm right or not.

You are partially right. Another very important use of the pointed-to type
is to determine how to interpret those bytes and which operations you can
perform on them.
If my assumption is correct, then may be I can guess why casting
a pointer to function to void* is undefined. The pointer points to
the starting address of the function, without knowing the whole
length of the function, so the pointer doesn't know how many
bytes could the pointer in charge of, right?

No. The size of the function is not a concern, because a void* is also in
charge of an unspecified number of bytes.
The reason lies in the support for architectures with separate code and data
memories, where you can have more functions than data items, or where a
function pointer needs additional information (for example security
attributes) that are not needed for data pointers.

Bart v Ingen Schenau
 
K

Keith Thompson

Nobody said:
However: I suggest that it would be legal for the implementation to print
all pointers as "?" if it can detect that the *scanf() functions aren't
used by the program.

Legal, yes. Sane, no.
 
K

Keith Thompson

Stanley Rice said:
But I try to print sizeof(void *) and sizeof(ptr2fun), supposing that
ptr2fun is a function pointer. It generate the same result, both are
4. So is your meaning that in some special cases, the size of function
pointer and the pointer to void * is different? And could you explain
to me when it occurs?

You've demonstrated that void* and ptr2fun have the same size *under
your implementation*. That says nothing about other implementations,
or about what the language standard requires.
 
K

Kenny McCormack

Legal, yes. Sane, no.

That doesn't matter around here, does it?

--
One of the best lines I've heard lately:

Obama could cure cancer tomorrow, and the Republicans would be
complaining that he had ruined the pharmaceutical business.

(Heard on Stephanie Miller = but the sad thing is that there is an awful lot
of direct truth in it. We've constructed an economy in which eliminating
cancer would be a horrible disaster. There are many other such examples.)
 
P

Peter Nilsson

Keith Thompson said:
Legal, yes. ...

I disagree. Implementation-defined does not mean anything goes.
I don't think '?' for all pointers can be said to be the 'value
of the pointer converted to a sequence of printing characters.'

Would you say puts() is free to only ever output '?' since no
strictly conforming program can read it back from stdout?
 
K

Keith Thompson

Peter Nilsson said:
I disagree. Implementation-defined does not mean anything goes.
I don't think '?' for all pointers can be said to be the 'value
of the pointer converted to a sequence of printing characters.'

Would you say puts() is free to only ever output '?' since no
strictly conforming program can read it back from stdout?

I concede; always printing "?" would not be conforming, since it
does not meaningfully satisfy the requirement (vague though that
requirement is).
 

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
474,085
Messages
2,570,597
Members
47,219
Latest member
Geraldine7

Latest Threads

Top