helen
helen

Reputation: 55

What if I use %d instead of %ld in c?

I am a beginner and look at the book "C primer plus" and was confused about this saying

"To print a long value, use the %ld format specifier. If int and long are the same size on your system, just %d will suffice, but your program will not work properly when transferred to a system on which the two types are different, so use the %ld specifier for long."

I tested it myself as the following code:

int num = 2147483647;
short num_short = 32767;
long num_long = 2147483647;
printf("int: %d; short: %d; long: %d", num, num_short, num_long);

the program worked okay.

I searched online and found this question:%d with Long Int An answer said:

it works because long int and int are actually the same numeric representation: four byte, two's complement. With another platform (for example x86-64 Linux), that might not be the case, and you would probably see some sort of problem

My computer is 64-bits. The int is 32-bits. The long int is 32-bits. The short int is 16-bits (I checked it. It's all right). So you can see that the int type and short int type is different. This answer also said it would cause error if these types have different numeric representation. So what does the author mean of his saying?

Upvotes: 1

Views: 2670

Answers (2)

Roberto Caboni
Roberto Caboni

Reputation: 7490

What the author of your book says is correct.

Your test invokes undefined behavior, as the standard doesn't specify what will happen when a wrong format specifier is used. It means that the implementation of each compiler will be free to interpret how to manage such cases.

Nevertheless, with some common sense (and with a little knowledge about how things work "in practice") the behavior you experience can be explained.

Every format specifier says to the compiler where, in the list of parameters, it can find the parameter to be printed. For this reason, and that's the core of your book's assertion, passing an integer with an unexpected length makes the following format specifiers retrieve the parameter in the wrong place.


Example 1: a sequence of 32 bits integers

Let's start with a "normal" sequence, in order to have a base example.

int a=1, b=2;
printf("%d %d\n", a, b);

The format specifies tells the compiler that two 4 bytes integers will be found after the format strings. The parameters are actually placed in the stack in the expected way

-------------------------------------------------
  ... format string | a (4 bytes) | b (4 bytes) |
-------------------------------------------------

Example 2: why printing a 64-bytes long with %d doesn't work?

Let's consider the following printf:

long int a=1;
int b=2;
printf("%d %d\n", a, b);

The format specifies tells the compiler that two 4 bytes integers will be found after the format strings. But the first parameter takes 8 bytes instead of 4

-------------------------------------------------------------
  ... format string | a (4 bytes) + (4 bytes) | b (4 bytes) |
-------------------------------------------------------------
                      ^             ^
                      Compiler      Compiler
                      expects 'a'   expects 'b'
                      here          here

So the output would be

1 0

because b is searched where the 4 most significant bytes of a are, and they are all 0s.


Example 3: why do printing a 16-bytes short with %d work?

Let's consider the following printf:

short int a=1;
int b=2;
printf("%d %d\n", a, b);

The format specifies tells the compiler that two 4 bytes integers will be found after the format strings. The first parameter takes only two bytes instead of 4, but... we are lucky, because on a 32 bits platform parameters are 4-bytes aligned!

---------------------------------------------------------------------
  ... format string | a (2 bytes) | (2 bytes PADDING) | b (4 bytes) |
---------------------------------------------------------------------
                      ^                               ^
                      Compiler                        Compiler
                      expects 'a'                     expects 'b'
                      here                            here

So the output would be

1 1

because b is searched in the correct place. We would have problems in the representation of a if the alignment was done with non-0 padding, but it's not the case.

So, the real difference in case of %d used for short is just the representation of signed bytes, as the sign bit is expected to be in the most significant one.

Upvotes: 2

klutt
klutt

Reputation: 31296

Whatever happens depends on the implementation. The standard is quite clear on this, and it does invoke undefined behavior.

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.

7.21.6.1p9

Roberto explained in detail why it "works" in his answer

Upvotes: 4

Related Questions