Printf question.

P

praeiji

Hi,

I was wondering something today. The following code :

unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?

Thanks,
 
U

usenet

praeiji said:
unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?

Both arguments get promoted to int before they are passed to printf()

_Ico
 
P

praeiji

Thanks,

But why are they typecasted to int? Does it come from gcc when it sees
"%d" and the printf function?
 
N

nelu

praeiji said:
Hi,

I was wondering something today. The following code :

unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?

Thanks,

Conversion Argument Converted Default Pre-
Specifier Type Value Base cision
%d int x (int)x 10 1

That means %d formats int. If you give it char and unsigned char it
will convert them to int.
 
J

Jack Klein

Hi,

I was wondering something today. The following code :

unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?

Thanks,

This has nothing to do with printf(), per se. It does not know the
difference between the original objects providing the values.

What you are seeing is the result of what the C standard calls the
"default argument promotions". These occur when calling a function
without a prototype in scope, or for the "..." arguments in a variadic
function.

In the case of integer types of lesser rank than int, the "integer
promotions" occur. Since a signed int can hold the value 200, the
value in the unsigned char 'a' is converted to the int value 200.

On your particular system, chars have 8 bits and 'plain' char is
signed. The binary representation of 200 in an 8-bit byte happens to
be the same as the 8-bit 2's complement representation of -56, and
that is the implementation-defined result of assigning the
out-of-range value to a signed 'plain' char.

The integer promotions take the 'plain' char value of -56 and convert
it to an int value of -56.

So the values of 200 and -56 are generated during argument evaluation,
before printf() is called.

On some platforms, char has more than 8 bits, and 200 would remain 200
in a 'plain' char or signed char. On some platforms, 'plain' char is
unsigned, not signed. On platforms with either of these
characteristics, the output would be "200, 200".

And on some platforms, the output would not appear at all because you
did not add a final '\n'.
 
U

usenet

praeiji said:
But why are they typecasted to int? Does it come from gcc when it sees
"%d" and the printf function?

No, they are not typecasted, but `promoted', which is not the same thing.
Promotion is what happens when you call a function that has no prototype, or
when a function with a variable number (variadic) of arguments like printf()
is called. With promotion, all arguments are converted to a generic 'bigger'
type: char and short to int, float to double.

Ico
 
K

Keith Thompson

Jack Klein said:
in comp.lang.c: [...]
unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?
[snip]

In the case of integer types of lesser rank than int, the "integer
promotions" occur. Since a signed int can hold the value 200, the
value in the unsigned char 'a' is converted to the int value 200.

Correction: since a signed int can hold any value of type unsigned
char, the value in the unsigned char 'a' is promoted to type int. The
promoted type doesn't depend on the value that happens to be in the
variable; it depends on which type can hold *any* possible value of
the type.
 
F

Flash Gordon

Keith said:
Jack Klein said:
in comp.lang.c: [...]
unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?
[snip]

In the case of integer types of lesser rank than int, the "integer
promotions" occur. Since a signed int can hold the value 200, the
value in the unsigned char 'a' is converted to the int value 200.

Correction: since a signed int can hold any value of type unsigned
char, the value in the unsigned char 'a' is promoted to type int.

<annoying pedant>
What, even on a system with CHAR_BIT==16 and sizeof(int)==1 ?
</annoying pedant>

Of course, you are only likely to find such systems in the embedded
world where you may well not have printf.
> The
promoted type doesn't depend on the value that happens to be in the
variable; it depends on which type can hold *any* possible value of
the type.

You are, of course, correct that is is purely a matter of type, not the
value the variable happens to contain.
 
C

Charles Richmond

No, they are not typecasted, but `promoted', which is not the same thing.
Promotion is what happens when you call a function that has no prototype, or
when a function with a variable number (variadic) of arguments like printf()
is called. With promotion, all arguments are converted to a generic 'bigger'
type: char and short to int, float to double.
Type promotion can also happen when you do mixed mode arithmetic.
 
J

Jack Klein

Jack Klein said:
in comp.lang.c: [...]
unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?
[snip]

In the case of integer types of lesser rank than int, the "integer
promotions" occur. Since a signed int can hold the value 200, the
value in the unsigned char 'a' is converted to the int value 200.

Correction: since a signed int can hold any value of type unsigned
char, the value in the unsigned char 'a' is promoted to type int. The
promoted type doesn't depend on the value that happens to be in the
variable; it depends on which type can hold *any* possible value of
the type.

Yes, thanks.
 
M

Malcolm

Flash Gordon said:
<annoying pedant>
What, even on a system with CHAR_BIT==16 and sizeof(int)==1 ?
</annoying pedant>

Of course, you are only likely to find such systems in the embedded world
where you may well not have printf.
But often you have vsprintf(), or you need to implement it.

The whole language does begin to break down when we push the limits of
ANSI's definition. For instance, should field-length parameters really be
size_t s?
 
E

Eric Sosman

Charles said:
Type promotion can also happen when you do mixed mode arithmetic.

Or even unmixed-mode arithmetic:

short x = 1, y = 2;
short z = x + y; /* see the "int"? */
 
J

Jordan Abel

But often you have vsprintf(), or you need to implement it.

The whole language does begin to break down when we push the limits of
ANSI's definition. For instance, should field-length parameters really be
size_t s?

You could take the cheap way out and do stuff along the lines of

sprintf(format,"%%%d.%df",width,precision>=0?precision:0);

c89 doesn't appear to provide for field-length parameters anyway - at
least the draft i have doesn't.
 
B

Bliss

praeiji said:
Hi,

I was wondering something today. The following code :

unsigned char a = 200;
char b = 200;
printf( "%d %d", a, b );

gives :

200, -56

How comes? I didn't tell printf that the first argument was unsigned
and it detected it on its own. It doesn't seem possible with varargs.
How is it possible?

That would happen if plain char on your machine is signed and char is
eight bits wide. The assignment b = 200 makes b -56.

Roger.
 
P

Peter Nilsson

Bliss said:
That would happen if plain char on your machine is signed and
char is eight bits wide. The assignment b = 200 makes b -56.

Your conditions are necessary, but not strictly sufficient to make b
receive the value of -56.

As the value 200 is outside the range of an 8-bit signed
plain char, the conversion is implementation defined.[*]
Even adding the condition that signed char has twos
complement representation is not sufficient to force a
value of -56 for b since an implementation is still
entitled to assign say 0 in such cases, if it chooses.

You can say it likely yielded -56 because most implementations
are two's complement and preserve the bitwise representation
(albeit with trunction or sign extension) when performing
conversions of an integer value which is outside the range of
the target type.

[*] C99 adds the possibility of an implementation defined signal.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top