0

I am learning C. As I went through pointers there I noticed some strange behavior which I can't get it. When casting character pointer to integer pointer, integer pointer holds some weird value, no where reasonably related to char or char ascii code. But while printing casted variable with '%c', it prints correct char value.

Printing with '%d' gives some unknown numbers.

printf("%d", *pt); // prints as unknown integer value that too changes for every run

But while printing as '%c' then

printf("%c", *pt); // prints correct casted char value

Whole Program:

int main() {

char f = 'a';
int *pt = (int *)&f;

printf("%d\n", *pt);
printf("%c\n", *pt);

return 0;
}

Please explain how char to int pointer casting works and explain the output value.

Edit:

If I make the below changes to the program, then output will be as expected. Please explain this too.

#include <stdio.h>

int main() {

char f = 'a';
int *pt = (int *)&f;

printf("%d\n", *pt);
printf("%c\n", *pt);

int val = (int)f;
printf("%d\n", val);
printf("%c", val);
return 0;
}

Output:

97
a
97
a

Please explain this behavior too.

  • 2
    Assume there are 4 bytes in an int. You've set one byte, the other three are indeterminate and it is undefined behavior to access them. – Retired Ninja May 21 '19 at 00:29
  • 2
    The line `int *pt = (int *)&f;` invokes at least 3 different types of undefined behavior. In other words, even though the language syntax allows you to do that, you aren't allowed to do that. Here's [some more information about undefined behavior](https://stackoverflow.com/questions/2397984). – user3386109 May 21 '19 at 00:31
  • 1 of the 4 bytes in the output of %d might include the ASCII code for 'a' and a 0. The other 2 bytes are undefined and reading then could cause a crash. Or the compiler could just print 4 smiley faces as when invoking undefined behaviour, you get whatever the compiler writers decided. – Michael Dorgan May 21 '19 at 00:31
  • @user3386109: People are allowed to do that. The C standard’s definition of “undefined behavior” is behavior upon which it imposes **no** requirements. It does not require people not to do it. This is important: Some behavior that is not defined by the C standard is defined by C implementations. These are **extensions** to the C language, which the C standard explicitly invites. (Casting a pointer to a single `char` to a pointer to an `int` is not such an extension; the point is that the C standard does not prohibit this, not that it is an extension.) – Eric Postpischil May 21 '19 at 00:36
  • If you made your `f` at least an array of 4 characters long on a 32-bit machine or 8 characters long on a 64-bit machine then it should act the same between runs. Of course, printing an interpreted int pointer as a char is also not a great idea and also is asking for trouble. `va_args` is another one of those areas not for the feint of heart... – Michael Dorgan May 21 '19 at 00:36
  • The section of the standard that both allows it for `char` and `int` and also prohibits it for `int` and *anything else* is [C11 Standard - §6.5 Expressions (p6,7)](http://port70.net/~nsz/c/c11/n1570.html#6.5p6) That said, allowing the cast to-from `char` does not make what you have done correct. – David C. Rankin May 21 '19 at 00:43
  • 2
    in general casting char* to int* and then using that int pointer is likely to break on every arctitecture that enforces int alignment, this code is probably OK as the stack will be int aligned, but adding another char variable could break it, refrerncing a pointer to unallocated memory (the bytes after f) is definately undefined bahaviour – Jasen May 21 '19 at 00:46
  • the correct way to perform this expeiment is to use a union, then you get implementation-defined behaviour, not undefined. – Jasen May 21 '19 at 00:49
  • Tip: Consider setting your compilation's warning level to `-Wall` or equivalent. It's best to do this early while writing a program so you can address a few issues as they come up rather than dealing with a flood. (Some people even set warnings to be treated as errors.) And if you do want to use a vendor extension, there might be a compiler flag to document it and suppress the warning. – Tom Blodget May 21 '19 at 23:28

3 Answers3

5

For what the C language specifies, this is just plain undefined behavior. You have a char sized region of memory from which you are reading an int; the result is undefined.

As for what is likely happening: The C runtime ends up dumping some random garbage on the stack before main is even executed. char f = 'a'; happens to rewrite one byte of the garbage to a known value, but the padding to align pt means the remaining bytes are never rewritten at all, and have "whatever the runtime left behind" in them. So when you read an int out, on a little endian system, the low byte equals the value of 'a', but the high bytes are whatever garbage happens to be left in the padding space.

As for why %c works, since the low byte is still the same, and %c only examines the low byte of the int provided, all the garbage is ignored, and things happen to work as expected. This only works on a little endian machine though; on a big endian machine, it would be the high byte initialized to 'a', but the low byte (garbage) would be printed by %c.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
1

You have define f as a char. This allocates typically 1 byte of storage in most of the hardware. You take the address of f, cast it to (int *) and assign it to an int * variable, pt. Size of integer depends on the underlying hardware - it could be 2 or 4 or even more. When you assign address of f to pt, the address that gets assigned to pt depends on factors such as int size and the alignment requirements. That is why when you print *pt, you see a garbage value. Actually, the ASCII value of 'a' is contained in the garbage, the position of which depends on the int size, endianness of the hardware, etc. If you print *pt with %x, you will see 61 in the output (61 hex is 97 in decimal).

Ravi S
  • 139
  • 3
0
<#include <stdio.h>
int main()
{

    //type casting in pointers

    int a = 500; //value is assgned
    int *p;   //pointer p
    p = &a;   //stores the address in the pointer
    printf("p=%d\n*p=%d", p, *p);
    printf("\np+1=%d\n*(p+1)=%d", p + 1, *(p + 1));

    char *p0;
    p0 = (char *)p;
    printf("\n\np0=%d\n*p0=%d", p0, *p0);

    return 0;
}
  • Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – DCCoder May 17 '21 at 18:27
  • @DCCoder already the theory were explained so code give more clarification on that and person who asked the q is also helpful by it . – vishal kumawat May 18 '21 at 04:27