简体   繁体   中英

Confusion regarding pointer size

This may be a noob question ..but this is really confusing me..

Below is some sample code

void main() {

    int a = 300;
    char *ptr = &a;
    int *intptr = &a;

    printf("%d\n %d\n", *ptr, *intptr);

}

output:
44
300

As per my understanding,why dereferencing *ptr prints 44 is due to the fact that char pointer is one byte and so it reads only 8 bits from the address of int...

But this question:What is the size of a pointer? states Regardless of what data type they are pointing to, they have fixed size

Am i missing some thing.Why dereferencing char pointer prints 44,if pointer size is same ?

First of all, your code is not valid C and it also invokes undefined behavior, so anything can happen. If your compiler didn't show you any diagnostic messages, you need to uninstall it and get a working one instead. You have the following bugs:

  • void main() will only work on freestanding implementations that specifically allow this form of main.
  • char *ptr = &a; is not a valid form of assignment in C. The pointers are not compatible (1) .
  • Printing a character with the %d format specifier invokes undefined behavior.

After fixing these bugs, we get:

#include <stdio.h>

int main (void)
{
  int a = 300;
  char *ptr = (char*)&a;
  int *intptr = &a;

  printf("%d\n %d\n", (int)*ptr, *intptr);
}

None of this prints the size of a pointer. You print the contents of the first byte in the int a , which you translate to a char , which may or may not be signed and possibly give an incorrect result (this part is endianess-dependent). And then you print the contents of the whole int a .

What you seem to want is to print the size of the pointers themselves:

printf("%zu %zu\n", sizeof ptr, sizeof intptr);

(1) C11 6.5.16.1 emphasis mine:

Constraints
One of the following shall hold:
/--/
- the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types , and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

Object pointers (eg pointers to anything besides a function) are typically the same size on most systems you're likely to come across, however there's no guarantee of that. That being said, even though the pointers may be the same size, the types that they point to are not.

For example, on a 64-bit Windows system, pointers are typically 8 bytes in size. In your example you have char * and an int * which are most likely both 8 bytes. The difference here is that dereferencing a char * will read/write 1 byte while dereferenceing an int * will read/write 4 bytes (assuming an int is 32 bit).

Assuming little endian byte ordering, a looks like this in memory:

  ------------------
a | 44 | 1 | 0 | 0 |
  ------------------

Both ptr and intptr contain the address of a . When dereferencing ptr , which is of type char * , it only looks at the first byte. In contrast, when dereferencing intptr , which is of type int * , it looks at all 4 bytes.

In this statement

printf("%d\n %d\n", *ptr, *intptr);

there are outputted not the pointers themselves but the data they point to.

For example 300 can be represented like 256 + 44 . So 44 can be stored in one byte while 256 can be stored in another byte. And this expression *ptr gives the value 44 stored in the byte pointed to by the pointer ptr .

On the other hand the pointer intptr points to the whole object of the type int and the expression *intptr gives the value 300.

If you want to output the addresses stored in the pointers you should write

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

To output sizes of the pointers you could write

printf("%zu\n %zu\n", sizeof( ptr ), sizeof( intptr ));

Take into account that according to the C Standard the function main without parameters shall be declared like

int main( void )

Also in this declaration you should use an explicit casting

char *ptr = ( char * )&a;

Here is a demonstrative program

#include <stdio.h>

int main(void) 
{
    int a = 300;
    char *ptr = ( char * )&a;
    int *intptr = &a;

    printf( "*ptr = %d, *intptr = %d\n", *ptr, *intptr );
    printf( "ptr = %p, intptr = %p\n", ( void * )ptr, ( void * )intptr );
    printf( "sizeof( ptr ) = %zu, sizeof( intptr ) = %zu\n", 
        sizeof( ptr ), sizeof( intptr ) );

    return 0;
}

Its output might look like

*ptr = 44, *intptr = 300
ptr = 0x7ffe5972613c, intptr = 0x7ffe5972613c
sizeof( ptr ) = 8, sizeof( intptr ) = 8

You introduce undefined behaviour if you cast a pointer to an object to a different type than that of the object AND access it then through this pointer.

Statement int a = 300 introduces an object of type int , char* ptr = &a introduces a pointer to an object of type char but let it point to an object of type int . This per se is not a problem, but dereferencing this pointer then through *ptr is undefined behaviour. And this does not have something to do with the printf - a statement like char x = *ptr would be UB, too. However, a statement like int x = *((int *)ptr) would be OK, as the ptr is casted back to the original type of the object it points to.

Concerning the sizes of pointers: The size of a pointer (ie the value necessary for storing a memory address to which the pointer points to) is fixed size; it's usually 4 bytes on a 32 bit system and 8 bytes on a 64 bit system. The size necessary for representing a memory address has nothing to do with the size of the object that resides at the respecite memory address to which the pointer points to.

The following example demonstrates this behaviour:

int main() {

    int a = 300;
    void *ptr = &a;
    int *intptr = &a;

    printf("%d %d\n", *((int*)ptr), *intptr);   
}

Output:

300 300

Indeed, on a little endian architecture, the LSB would appear first in memory, thus to store 300, memory looks like

44 , 1 , 0 , 0  (for a size 4 int)

The

printf("%d\n %d\n", *ptr, *intptr);

doesn't print the pointer sizes (which are likely the same), it prints the dereferenced pointers, values of one byte, a char, then the int value.

To print the pointer sizes

printf ("%zu\n%zu\n", sizeof(ptr), sizeof(intptr));

Code

#include <stdio.h>
#include <stdint.h>

unsigned int
trans(unsigned char c){
  if ('0' <=c && c <= '9') return c - '0';
  if ('A' <=c && c <= 'F') return c - 'A' + 0x0A;
  if ('a' <=c && c <= 'f') return c - 'a' + 0x0A;
  return 0;
}

uint16_t
hex_to_uint16(const char* s) {
  char *p = (char*) s;
  uint16_t v = 0;
  while (*p) {
    if (p > s) v = v << 4;
    v += trans(*p);
    p++;
  }
  return v;
}

int main (void)
{

  int n = 1;
    // little endian if true
    if(*(char *)&n == 1) {printf("little\n");}

  int a = 300;
  char *ptr =  (char*)&a;
  int *intptr = &a;

    printf("charSize:%zu intSize:%zu\n", sizeof (char), sizeof (int));
    printf("PcharSize:%zu PintSize:%zu\n", sizeof (ptr), sizeof (intptr));


  //printf("Hex: %x, Decimal: %d\n", 0x2c, (int)0x2c ); 

  //printf("int: %d\n", hex_to_uint16("2c"));
    //printf("300H: %x\n", (a));


    printf("PcharAddr: %p\nPintAddr: %p\n", ptr, intptr);


  printf("int: %d\n", *intptr);


  printf("LSB  |     |     |  MSB|\n");
  printf("  0  |  1  |  2  |  3  |\n");
  printf("------------------------\n");
  printf("Dec\n");
  printf(" %d     %d     %d     %d\n", *(ptr), *(ptr+1), *(ptr+2), *(ptr+3));
  printf("Hex\n");
  printf(" %x     %x     %x     %x\n", *(ptr), *(ptr+1), *(ptr+2), *(ptr+3));



    printf("To Big Endian:\n%.2x%x%x%x\n", (uint8_t)*(ptr+3), (uint8_t)*(ptr+2), (uint8_t)*(ptr+1), (uint8_t)*(ptr));

  ///https://stackoverflow.com/questions/19275955/convert-little-endian-to-big-endian
    /*
     * chux aswer
    uint32_t num = 300;
    uint8_t b[4];

    b[0] = (uint8_t) (num >>  0u);
    b[1] = (uint8_t) (num >>  8u);
    b[2] = (uint8_t) (num >> 16u);
    b[3] = (uint8_t) (num >> 24u);

  printf("%x%x%x%x\n", b[3], b[2], b[1], b[0]);

  */

    return 0;
}

Compile, Run

gcc -Wall -Wextra te.c -o te && ./te

no, no, no

As per my understanding,why dereferencing *ptr prints 44 is due to the fact that char pointer is one byte and so it reads only 8 bits from the address of int...

char is one byte, not char pointer. If you want to print pointer you should

printf("%p\n %p\n", ptr, intptr);

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