By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,171 Members | 980 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,171 IT Pros & Developers. It's quick & easy.

strange use of format specifier in printf

P: n/a
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?

Jun 23 '06 #1
Share this Question
Share on Google+
18 Replies


P: n/a

Money wrote:
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?


No. It will print them in decimal though, not as characters.

I suggest you look up what char is promoted to when passed as an
argument.

Tom

Jun 23 '06 #2

P: n/a

"Money" <sp*********@gmail.com> wrote in message
news:11*********************@m73g2000cwd.googlegro ups.com...
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?

Yes. This has to be the presumption against a hyperlink versus the OP
taking time to tailor his argument to the forum. ciao, f
Jun 23 '06 #3

P: n/a
Money wrote:
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?


On a platform with signed 'char' type, when 'char' values are passed as
arguments for '...' (ellipsis) parameters, they are first promoted to 'int'
values. So it's 'int' values that are actually passed. And there's nothing wrong
with using '%d' format specifier with 'int' values.

On a platform with unsigned 'char' type, it is possible that 'int' is not large
enough to hold all values of 'char' and 'char' will be promoted to 'unsigned
int' instead. In this particular case the code would lead to undefined behavior,
since it is illegal to use '%d' format specifier with 'unsigned int' values.

--
Best regards,
Andrey Tarasevich
Jun 23 '06 #4

P: n/a
Tom St Denis wrote:
Money wrote:
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?


No. It will print them in decimal though, not as characters.

I suggest you look up what char is promoted to when passed as an
argument.

Tom


But we are telling printf to print 32-bits(on my system), and char is
not 32-bits(I know it can be but atleast it's not on my system)

Jun 23 '06 #5

P: n/a

Andrey Tarasevich wrote:
Money wrote:
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?


On a platform with signed 'char' type, when 'char' values are passed as
arguments for '...' (ellipsis) parameters, they are first promoted to 'int'
values. So it's 'int' values that are actually passed. And there's nothing wrong
with using '%d' format specifier with 'int' values.

On a platform with unsigned 'char' type, it is possible that 'int' is not large
enough to hold all values of 'char' and 'char' will be promoted to 'unsigned
int' instead. In this particular case the code would lead to undefined behavior,
since it is illegal to use '%d' format specifier with 'unsigned int' values.

--
Best regards,
Andrey Tarasevich


Thanks..I got it.

Jun 23 '06 #6

P: n/a
Money wrote:
I suggest you look up what char is promoted to when passed as an
argument.


But we are telling printf to print 32-bits(on my system), and char is
not 32-bits(I know it can be but atleast it's not on my system)


AHEM
I suggest you look up what char is promoted to when passed as an
argument.


Thanks for playing the usenet game. Can you now play the research
game?

Tom

Jun 23 '06 #7

P: n/a
>> I suggest you look up what char is promoted to when passed as an
argument.

Tom


But we are telling printf to print 32-bits(on my system), and char is
not 32-bits(I know it can be but atleast it's not on my system)


But what is char promoted to when passed as an argument on your
system?

Gordon L. Burditt
Jun 23 '06 #8

P: n/a
Andrey Tarasevich wrote:
...
On a platform with unsigned 'char' type, it is possible that 'int' is not
large enough to hold all values of 'char' and 'char' will be promoted
to 'unsigned int' instead. In this particular case the code would lead
to undefined behavior, since it is illegal to use '%d' format specifier
with 'unsigned int' values.


On such a hosted implementation, you'll likely find considerably
more problems than just printing a char. The C standards seem
to let the QoI gods rule out the possibility of such implementations
existing.

[Different story for freestanding implementations though. Real
implementations with CHAR_MAX == UINT_MAX exist, though
none which include <stdio.h> support, AFAIK.]

--
Peter

Jun 23 '06 #9

P: n/a
How about this solution

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int TestByteOrder()
{
int x = 0x0001;
char *y = (char *) &x;
return(y[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}

Jun 23 '06 #10

P: n/a
Money said:
How about this solution

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int TestByteOrder()
{
int x = 0x0001;
char *y = (char *) &x;
return(y[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}


This fails to identify middle-endian systems.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 23 '06 #11

P: n/a
Richard Heathfield wrote:
Money said:
How about this solution

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int TestByteOrder()
{
int x = 0x0001;
char *y = (char *) &x;
return(y[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}


This fails to identify middle-endian systems.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)

Just forgetting about any other ordering except these two. Will it work
fine if char is more than 8 bits?

Jun 23 '06 #12

P: n/a
"Money" <sp*********@gmail.com> writes:
Richard Heathfield wrote:
Money said:
> How about this solution
>
> #define BIG_ENDIAN 0
> #define LITTLE_ENDIAN 1
>
> int TestByteOrder()
> {
> int x = 0x0001;
> char *y = (char *) &x;
> return(y[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
> }


This fails to identify middle-endian systems.


Just forgetting about any other ordering except these two. Will it work
fine if char is more than 8 bits?


Maybe.

A very minor point: I'd write the initializer for x as "0x1" or just
"1". The three leading zeros seem to imply that int is 16 bits, which
of course it may or may not be.

If char is at least 16 bits, then it's possible that sizeof(int)==1;
in that case, int has no meaningful byte order, but your function will
return LITTLE_ENDIAN.

If int has at least CHAR_BIT padding bits at its lowest address, your
function will BIG_ENDIAN if the padding bits happen to be set to 0, or
possibly some meaningless result if the padding bits are set to some
arbitrary value.

Your function tests the byte order of type int. It's not
inconceivable that other integer types could have different byte
orders.

None of these problems are likely to turn up on any modern hosted
system.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 23 '06 #13

P: n/a
Richard Heathfield posted:
Money said:
How about this solution

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int TestByteOrder()
{
int x = 0x0001;
char *y = (char *) &x;
return(y[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}


This fails to identify middle-endian systems.

Start off with an unsigned integer, and set its value to zero.

Then set its second LSB to 1 (achieve this by taking 1 and shifting it
CHAR_BIT places to the left, and then OR-ing it with the original
variable).

Then set its third LSB to 2. Then set its forth LSB to 3. And so on.

Then use a char pointer to go through the unsigned integer's bytes. The
byte with the value 0 is the LSB. The byte with the value 1 is the second
LSB. And so on. (But beware of padding within the unsigned integer!).

I've already written such code many times but I'm working off a laptop
and don't have my code directory with me...
Jun 23 '06 #14

P: n/a
Keith Thompson wrote:
If char is at least 16 bits, then it's possible that sizeof(int)==1;
in that case, int has no meaningful byte order, but your function will
return LITTLE_ENDIAN.
How is it possible for sizeof(int)==1. I am not able to understand.
If int has at least CHAR_BIT padding bits at its lowest address, your
function will BIG_ENDIAN if the padding bits happen to be set to 0, or
possibly some meaningless result if the padding bits are set to some
arbitrary value.


I really didn't understood that. Please can you explain in simpler words

Jun 24 '06 #15

P: n/a
"Money" <sp*********@gmail.com> writes:
Keith Thompson wrote:
If char is at least 16 bits, then it's possible that sizeof(int)==1;
in that case, int has no meaningful byte order, but your function will
return LITTLE_ENDIAN.


How is it possible for sizeof(int)==1. I am not able to understand.


char must be at least 8 bits (CHAR_BIT >= 8).

int must be at least 16 bits (CHAR_BIT * sizeof(int) >= 16). [1]

An implementation with CHAR_BIT==16 and sizeof(int)==1 would satisfy
these requirements.

Note that sizeof yields the size of its argument in bytes. In C, a
"byte" is by definition the size of a char, so sizeof(char) == 1 by
definition, however many bits that happens to be. (It's common these
days to use the term "byte" to mean exactly 8 bits, but that's not how
C uses the term; a better word for exactly 8 bits is "octet".)
If int has at least CHAR_BIT padding bits at its lowest address, your
function will BIG_ENDIAN if the padding bits happen to be set to 0, or
possibly some meaningless result if the padding bits are set to some
arbitrary value.


I really didn't understood that. Please can you explain in simpler words


Here's an example. Suppose CHAR_BIT==8, and sizeof(int)==4 (32 bits),
but only the high-order 24 bits contribute to the value; the low-order
8 bits are ignored. These 8 bits are called "padding bits". Suppose
the byte order is little-endian. Then the value 0x654321, for example,
would be represented by the byte values (0x00, 0x21, 0x43, 0x65), shown
from lowest to highest addresses within the word.

The proposed code sets an int to the value 1, which on our
hypothetical system would be represented as (0x00, 0x01, 0x00, 0x00).
It then looks at the first byte (at the lowest address) of the
representation. Seeing the value 0x00, it assumes, incorrectly, that
the 1 byte was stored at the other end of the word, and that the
machine is big-endian.

(I *think* I got this right.)

[1] The standard doesn't actually say direcly that int is at least 16
bits. It says that the range of values it can represent is at
least -32767 .. +32767. That, and the fact that a binary
represention is required, imply that it's at least 16 bits.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 24 '06 #16

P: n/a
On 2006-06-24, Money <sp*********@gmail.com> wrote:
Keith Thompson wrote:
If char is at least 16 bits, then it's possible that sizeof(int)==1;
in that case, int has no meaningful byte order, but your function will
return LITTLE_ENDIAN.


How is it possible for sizeof(int)==1. I am not able to understand.


int is guaranteed to be at least 16 bits. char is guaranteed to be
at least 8 bits, and sizeof (char) will always equal one. Therefore,
if both a char and an int are 16 bits (or any number above that),
sizeof (int) will equal one.
If int has at least CHAR_BIT padding bits at its lowest address, your
function will BIG_ENDIAN if the padding bits happen to be set to 0, or
possibly some meaningless result if the padding bits are set to some
arbitrary value.


I really didn't understood that. Please can you explain in simpler words


Padding bits are unused bits in a variable that don't actually hold
a value. They might contain metadata about the variable, and so if
they are corrupted, no one knows what will happen. (It won't be UB
that I know of, but it may not be what you expect.)

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.
Jun 24 '06 #17

P: n/a
Andrew Poelstra <ap*******@localhost.localdomain> writes:
[...]
Padding bits are unused bits in a variable that don't actually hold
a value. They might contain metadata about the variable, and so if
they are corrupted, no one knows what will happen. (It won't be UB
that I know of, but it may not be what you expect.)


Padding bits are defined only for integer types. (For other types,
the standard doens't say enough about their representation for the
concept to be meaningful.)

Padding bits do not contribute to the value of an object. Certain
values of padding bits might create a trap representation; accessing
an object that contains a trap representation invokes undefined
behavior.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 24 '06 #18

P: n/a
On Thu, 22 Jun 2006 21:44:42 -0700, Andrey Tarasevich
<an**************@hotmail.com> wrote in comp.lang.c:
Money wrote:
Here in this thread
http://groups.google.co.in/group/com...b0dbf76f3e02e3

Tydr Schnubbis in 3rd reply used %d for printing char's...isn't it
wrong?


On a platform with signed 'char' type, when 'char' values are passed as
arguments for '...' (ellipsis) parameters, they are first promoted to 'int'
values. So it's 'int' values that are actually passed. And there's nothing wrong
with using '%d' format specifier with 'int' values.

On a platform with unsigned 'char' type, it is possible that 'int' is not large
enough to hold all values of 'char' and 'char' will be promoted to 'unsigned
int' instead. In this particular case the code would lead to undefined behavior,
since it is illegal to use '%d' format specifier with 'unsigned int' values.


That is not entirely true. It is quite legal to pass an unsigned int
type to *printf() with a conversion specifier for the corresponding
signed type, and vice versa, provided that the value is within the
range of values that can be held in both types.

This snippet, assuming correct header inclusion:

void func()
{
int si = 2;
int ui = 2;

printf("\n%d %u\n", ui, si);
}

....must produce the output "2 2".

Passing a negative signed integer type to printf() with an unsigned
conversion specifier, or passing an unsigned integer type with a value
greater than TYPE_MAX with a signed conversion specifier is undefined.

You can also deduce from the standard that the common value range
defined solution actually applies to any function in C.

You can pass a signed int type (int or larger) to a function expecting
the corresponding unsigned type, or an unsigned type (int or larger)
to a function expecting the corresponding signed type, as long as the
value of type actually passed is in the range 0 through TYPE_MAX (not
UTYPE_MAX) inclusive.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Jun 24 '06 #19

This discussion thread is closed

Replies have been disabled for this discussion.