简体   繁体   中英

typecasting a pointer to an int .

I can't understand the output of this program . What I get of it is , that , first of all , the pointers p, q ,r ,s were pointing towards null .

Then , there has been a typecasting . But how the heck , did the output come as 1 4 4 8 . I might be very wrong in my thoughts . So , please correct me if I am wrong .

int main()
{

    int a, b, c, d; 
    char* p = (char*)0; 
    int *q = (int *)0; 
    float* r = (float*)0; 
    double* s = (double*)0; 

    a = (int)(p + 1); 
    b = (int)(q + 1);
    c = (int)(r + 1);
    d = (int)(s + 1);

    printf("%d %d %d %d\n", a, b, c, d); 

    _getch();
    return 0; 
}

Pointer arithmetic, in this case adding an integer value to a pointer value, advances the pointer value in units of the type it points to. If you have a pointer to an 8-byte type, adding 1 to that pointer will advance the pointer by 8 bytes.

Pointer arithmetic is valid only if both the original pointer and the result of the addition point to elements of the same array object, or just past the end of it.

The way the C standard describes this is ( N1570 6.5.6 paragraph 8):

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.
[...]
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

A pointer just past the end of an array is valid, but you can't dereference it. A single non-array object is treated as a 1-element array.

Your program has undefined behavior. You add 1 to a null pointer. Since the null pointer doesn't point to any object, pointer arithmetic on it is undefined.

But compilers aren't required to detect undefined behavior, and your program will probably treat a null pointer just like any valid pointer value, and perform arithmetic on it in the same way. So if the null pointer points to address 0 (this is not guaranteed, BTW, but it's very common), then adding 1 to it will probably give you a pointer to address N , where N is the size in bytes of the type it points to.

You then convert the resulting pointer to int (which is at best implementation-defined, will lose information if pointers are bigger than int , and may yield a trap representation ) and you print the int value. The result, on most systems, will probably show you the sizes of char , int , float , and double , which are commonly 1, 4, 4, and 8 bytes, respectively.

Your program's behavior is undefined, but the way it actually behaves on your system is typical and unsurprising.

Here's a program that doesn't have undefined behavior that illustrates the same point:

#include <stdio.h>
int main(void) {

    char c;
    int i;
    float f;
    double d;

    char   *p = &c;
    int    *q = &i;
    float  *r = &f;
    double *s = &d;

    printf("char:   %p --> %p\n", (void*)p, (void*)(p + 1));
    printf("int:    %p --> %p\n", (void*)q, (void*)(q + 1));
    printf("float:  %p --> %p\n", (void*)r, (void*)(r + 1));
    printf("double: %p --> %p\n", (void*)s, (void*)(s + 1));

    return 0; 
}

and the output on my system:

char:   0x7fffa67dc84f --> 0x7fffa67dc850
int:    0x7fffa67dc850 --> 0x7fffa67dc854
float:  0x7fffa67dc854 --> 0x7fffa67dc858
double: 0x7fffa67dc858 --> 0x7fffa67dc860

The output is not as clear as your program's output, but if you examine the results closely you can see that adding 1 to a char* advances it by 1 byte, an int* or float* by 4 bytes, and a double* by 8 bytes. (Other than char , which by definition has a size of 1 bytes, these may vary on some systems.)

Note that the output of the "%p" format is implementation-defined, and may or may not reflect the kind of arithmetic relationship you might expect. I've worked on systems (Cray vector computers) where incrementing a char* pointer would actually update a byte offset stored in the high-order 3 bits of the 64-bit word. On such a system, the output of my program (and of yours) would be much more difficult to interpret unless you know the low-level details of how the machine and compiler work.

But for most purposes, you don't need to know those low-level details. What's important is that pointer arithmetic works as it's described in the C standard. Knowing how it's done on the bit level can be useful for debugging (that's pretty much what %p is for), but is not necessary to writing correct code.

Adding 1 to a pointer advances the pointer to the next address appropriate for the pointer's type.

When the (null)pointers+1 are recast to int, you are effectively printing the size of each of the types being pointed to by the pointers.

printf("%d %d %d %d\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double) );

does pretty much the same thing. If you want to increment each pointer by only 1 , you'll need to cast them to (char *) before incrementing them to let the compiler know ,则需要在将它们递增之前将它们强制转换为(char *)以使编译器知道

Search for information about pointer arithmetic to learn more.

You're typecasting the pointers to primitive datatypes rather type casting them to pointers themselves and then using * (indirection) operator to indirect to that variable value. For instance, (int)(p + 1); means p ; a pointer to constant, is first incremented to next address inside memory ( 0x1 ), in this case. and than this 0x1 is typecasted to an int . This totally makes sense.

The output you get is related to the size of each of the relevant types. When you do pointer arithmetic as such, it increases the value of the pointer by the added value times the base type size. This occurs to facilitate proper array access.

Because the size of char , int , float , and double are 1, 4, 4, and 8 respectively on your machine, those are reflected when you add 1 to each of the associated pointers.

Edit:

Removed the alternate code which I thought did not exhibit undefined behavior, which in fact did.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM