Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading signed char using %u

#include <stdio.h>

int main() {
    int i,n;
    int a = 123456789;

    void *v = &a;

    unsigned char *c = (unsigned char*)v;

    for(i=0;i< sizeof a;i++) {
        printf("%u  ",*(c+i));
    }

    char *cc = (char*)v;
    printf("\n %d", *(cc+1));

    char *ccc = (char*)v;
    printf("\n %u \n", *(ccc+1));

}

This program generates the following output on my 32 bit Ubuntu machine.

21  205  91  7  
-51
4294967245

First two lines of output I can understand =>

  • 1st Line : sequence of storing of bytes in memory.
  • 2nd Line : signed value of the second byte value (2's complement).
  • 3rd Line : why such a large value ?

please explain the last line of output. WHY three bytes of 1's are added because (11111111111111111111111111001101) = 4294967245 .

like image 989
Debashish Avatar asked Apr 01 '16 07:04

Debashish


People also ask

How do I take unsigned char input?

unsigned char ch = 'a'; Initializing an unsigned char: Here we try to insert a char in the unsigned char variable with the help of ASCII value. So the ASCII value 97 will be converted to a character value, i.e. 'a' and it will be inserted in unsigned char.

What is the value of signed char?

All signed character values range from -128 to 127. All unsigned character values range from 0 to 255. The /J compiler option changes the default type for char from signed char to unsigned char .

Is %d signed or unsigned?

'%u' treats the integer as unsigned, whereas '%d' treats the integer as signed.

What is the use of signed char in C++?

Some properties of the signed char data type are: It is generally used to store 8-bit characters. Being a signed data type, it can store positive values as well as negative values. Size of 8 bits is occupied where 1 bit is used to store the sign of the value.


Video Answer


2 Answers

Apparently your compiler uses signed characters and it is a little endian, two's complement system.

123456789d = 075BCD15h
Little endian: 15 CD 5B 07

Thus v+1 gives value 0xCD. When this is stored in a signed char, you get -51 in signed decimal format.

When passed to printf, the character *(ccc+1) containing value -51 first gets implicitly type promoted to int, because variadic functions like printf has a rule stating that all small integer parameters will get promoted to int (the default argument promotions). During this promotion, the sign is preserved. You still have value -51, but for a 32 bit signed integer, this gives the value 0xFFFFFFCD.

And finally the %u specifier tells printf to treat this as an unsigned integer, so you end up with 4.29 bil something.

The important part to understand here is that %u has nothing to do with the actual type promotion, it just tells printf how to interpret the data after the promotion.

like image 115
Lundin Avatar answered Sep 19 '22 14:09

Lundin


-51 store in 8 bit hex is 0xCD. (Assuming 2s compliment binary system)

When you pass it to a variadic function like printf, default argument promotion takes place and char is promoted to int with representation 0xFFFFFFCD (for 4 byte int).

0xFFFFFFCD interpreted as int is -51 and interpreted as unsigned int is 4294967245.

Further reading: Default argument promotions in C function calls


please explain the last line of output. WHY three bytes of 1's are added

This is called sign extension. When a smaller signed number is assigned (converted) to larger number, its signed bit get's replicated to ensure it represents same number (for example in 1s and 2s compliment).


Bad printf format specifier
You are attempting to print a char with specifier "%u" which specifies unsigned [int]. Arguments which do not match the conversion specifier in printf is undefined behavior from 7.19.6.1 paragraph 9.

If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

Use of char to store signed value
Also to ensure char contains signed value, explicitly use signed char as char may behave as signed char or unsigned char. (In latter case, output of your snippet may be 205 205). In gcc you can force char to behave as unsigned char with -funsigned-char option.

like image 21
Mohit Jain Avatar answered Sep 22 '22 14:09

Mohit Jain