Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #41226 > unrolled thread
| Started by | jononanon@googlemail.com |
|---|---|
| First post | 2014-03-01 01:29 -0800 |
| Last post | 2014-03-01 18:55 +0000 |
| Articles | 20 on this page of 26 — 14 participants |
Back to article view | Back to comp.lang.c
why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:29 -0800
Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:42 -0800
Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 01:54 -0800
Re: why printf("%d", arg) works with arg of type int, short, char Barry Schwarz <schwarzb@dqel.com> - 2014-03-01 07:21 -0800
Re: why printf("%d", arg) works with arg of type int, short, char gazelle@shell.xmission.com (Kenny McCormack) - 2014-03-01 15:51 +0000
Re: why printf("%d", arg) works with arg of type int, short, char Richard <rgrdev_@gmail.com> - 2014-03-01 17:50 +0100
Re: why printf("%d", arg) works with arg of type int, short, char gazelle@shell.xmission.com (Kenny McCormack) - 2014-03-01 18:36 +0000
Re: why printf("%d", arg) works with arg of type int, short, char Melzzzzz <mel@zzzzz.invalid> - 2014-03-01 11:22 +0100
Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 02:39 -0800
Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 19:44 -0800
Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 02:34 -0800
Re: why printf("%d", arg) works with arg of type int, short, char jononanon@googlemail.com - 2014-03-01 02:49 -0800
Re: why printf("%d", arg) works with arg of type int, short, char James Kuyper <jameskuyper@verizon.net> - 2014-03-01 09:10 -0500
Re: why printf("%d", arg) works with arg of type int, short, char <william@wilbur.25thandClement.com> - 2014-03-01 15:38 -0800
Re: why printf("%d", arg) works with arg of type int, short, char Keith Thompson <kst-u@mib.org> - 2014-03-01 19:47 -0800
Re: why printf("%d", arg) works with arg of type int, short, char <william@wilbur.25thandClement.com> - 2014-03-01 21:12 -0800
Re: why printf("%d", arg) works with arg of type int, short, char Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2014-03-02 07:47 -0700
Re: why printf("%d", arg) works with arg of type int, short, char Kaz Kylheku <kaz@kylheku.com> - 2014-03-02 20:53 +0000
Re: why printf("%d", arg) works with arg of type int, short, char jgk@panix.com (Joe keane) - 2014-03-04 00:23 +0000
Re: why printf("%d", arg) works with arg of type int, short, char Kaz Kylheku <kaz@kylheku.com> - 2014-03-04 00:33 +0000
Re: why printf("%d", arg) works with arg of type int, short, char glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-03-04 00:45 +0000
Re: why printf("%d", arg) works with arg of type int, short, char jgk@panix.com (Joe keane) - 2014-03-05 04:07 +0000
Re: why printf("%d", arg) works with arg of type int, short, char Barry Schwarz <schwarzb@dqel.com> - 2014-03-05 10:07 -0800
Re: why printf("%d", arg) works with arg of type int, short, char "BartC" <bc@freeuk.com> - 2014-03-01 11:12 +0000
Re: why printf("%d", arg) works with arg of type int, short, char Eric Sosman <esosman@comcast-dot-net.invalid> - 2014-03-01 10:54 -0500
Re: why printf("%d", arg) works with arg of type int, short, char glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-03-01 18:55 +0000
Page 1 of 2 [1] 2 Next page →
| From | jononanon@googlemail.com |
|---|---|
| Date | 2014-03-01 01:29 -0800 |
| Subject | why printf("%d", arg) works with arg of type int, short, char |
| Message-ID | <fc5dad84-08d7-4c7b-bd56-5ce49b177b1b@googlegroups.com> |
Hi there!
Check this out -> the following code always works:
printf("%d %d %d", (char)'\1', (short)2, 3);
// prints: 1 2 3
So a conversion specifier of %d works with type int, or "SMALLER" integer-types (short or char) !!!
Why does this work??
Is my explanation correct?
->
With printf("%d", (char) '\1')
the argument 1 lands on the stack not as char parameter, but as a parameter promoted to int, and the library code that handles the access to the parameter uses va_arg(ap, int) to access it. You can never use va_arg(ap, char) -> that would distroy a consistent handling of the stack-parameters!
When handling parameters on the stack, the size from one parameter to the next is never smaller than an int. (Even when NOT using variable arguments. Right? -> ref in C-std??)
Is this called argument promotion?
Demo:
/*
demonstration that char on stack nonetheless occupies the space of an int!
Not only does it occupy the space of an int, but all bytes comprising that int are set correctly! not just the single byte corresponding the the char.
(How does one call this: argument promotion????
Or is this part of integer promotion of a literal????)
*/
int func(char a, char b, char c)
{
const char *p = &a;
printf("a=%d\n"
"b=%d\n"
"c=%d\n", p[0],
p[-(int)sizeof(int)],
p[-(int)sizeof(int) * 2]);
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
If you want to do something like this portable, please use stdarg.h instead!
*/
}
Now, since printf("%d", arg) with its variable argument list, is implemented in the C library with stdarg.h's va_arg(ap, type)
and type may not be a "smaller" type than int, it so happens that the particular code for handling the conversion specifier "%d" uses va_arg(ap, int).
And that's the explanation!
Is it correct?
Can someone point out relevant parts of the C11 standard, that show that this handling of parameters in the stack must never occupy space of less than sizeof(int)??
And: ahhh... is this a issue of handling the stack; OR part of integer promotion of char-literals?? Two separate issues, or one and the same??
Examples with questions:
1)
printf("%d", '\1');
Here '\1' is promoted to int (integer promotion) and then put on the stack as integer?
2)
printf("%d", (char)'\1');
Does normal integer promotion of the literal char occur here? I think no.
Here a different type of promotion occurs, which is the one of handling the parameter stack??
I realize that I'm a bit confused, and may have things half-correct or so...?
Can someone give a good explanation.
Thanks so much!!
J.
[toc] | [next] | [standalone]
| From | jononanon@googlemail.com |
|---|---|
| Date | 2014-03-01 01:42 -0800 |
| Message-ID | <53fa11c2-6129-4171-8284-e5a796901f61@googlegroups.com> |
| In reply to | #41226 |
In func() above
Note that the code also "works" (yes yes... use stdarg.h instead!) when p is changed to be an int-pointer!!!
int func(char a, char b, char c)
{
const int *p = &a; // difference to prev: int pointer!!!!
printf("a=%d\n"
"b=%d\n"
"c=%d\n", p[0],
p[-(int)sizeof(int)],
p[-(int)sizeof(int) * 2]);
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
If you want to do something like this portable, please use stdarg.h instead!
*/
}
[toc] | [prev] | [next] | [standalone]
| From | jononanon@googlemail.com |
|---|---|
| Date | 2014-03-01 01:54 -0800 |
| Message-ID | <416f2444-8530-4622-bdcb-5cdf2d4e16f2@googlegroups.com> |
| In reply to | #41229 |
Ah damn, I've found some mistakes that have crept in...
I wrote:
"but all bytes comprising that int are set correctly! not just the single byte corresponding the the char."
This is not correct. Rather:
Only the space the char occupies on the stack is sizeof(int), but NOT ALL BYTES comprising that int are correctly set to correspond to the value of the char.
Proof is a FIX OF MY 2ND POST ABOVE (which was incorrect):
int func(char a, char b, char c)
{
const int *p = &a; // difference to prev: int pointer!!!!
- hide quoted text -
printf("a=%d\n"
"b=%d\n"
"c=%d\n", p[0],
p[-1], // FIX
p[-2]); // FIX
/* don't do this. might probably work on x86 with gcc (but again: don't do this)
If you want to do something like this portable, please use stdarg.h instead!
*/
}
This shows that the other bytes that are part of the stack-space (sizeof(int)), are not set correctly!
So then:
only when using variable arguments, are arguments of type char (or short) placed on the stack as correspondingly promoted int.
Ahhhh.... Sortof correct????? Maby??
[toc] | [prev] | [next] | [standalone]
| From | Barry Schwarz <schwarzb@dqel.com> |
|---|---|
| Date | 2014-03-01 07:21 -0800 |
| Message-ID | <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com> |
| In reply to | #41230 |
On Sat, 1 Mar 2014 01:54:53 -0800 (PST), jononanon@googlemail.com
wrote:
>Ah damn, I've found some mistakes that have crept in...
>
>I wrote:
>"but all bytes comprising that int are set correctly! not just the single byte corresponding the the char."
>
>This is not correct. Rather:
>Only the space the char occupies on the stack is sizeof(int), but NOT ALL BYTES comprising that int are correctly set to correspond to the value of the char.
There is no requirement for the char to occupy sizeof(int) bytes on
the stack. This is a characteristic of your implementation that may
or may not be true on other implementations.
>
>Proof is a FIX OF MY 2ND POST ABOVE (which was incorrect):
>
>int func(char a, char b, char c)
>{
> const int *p = &a; // difference to prev: int pointer!!!!
If a is not aligned properly for an int, then this would invoke
undefined behavior.
>- hide quoted text -
> printf("a=%d\n"
> "b=%d\n"
> "c=%d\n", p[0],
Since p[0] is an int but it points to a char, any "excess" bytes not
part of a that are accessed to evaluate the int are indeterminate and
therefore this invokes undefined behavior.
> p[-1], // FIX
When a pointer points to a scalar object, that object can be treated
as an array of 1. (This is why p[0] is valid.) However, you are not
allowed to evaluate a subscript expression where the subscript is
outside the range of the array. (In this case, the only valid
subscript is 0.) Doing so invokes undefined behavior.
> p[-2]); // FIX
>/* don't do this. might probably work on x86 with gcc (but again: don't do this)
One of the worst manifestations of undefined behavior is doing what
you expect, thus leaving you with the mistaken belief that you have
accomplished your task.
> If you want to do something like this portable, please use stdarg.h instead!
What do you think stdarg.h has to do with using an invalid subscript?
>*/
>}
>
>
>This shows that the other bytes that are part of the stack-space (sizeof(int)), are not set correctly!
No, it shows that invoking undefined behavior can reinforce your
preconceived assumptions.
If you wanted to examine bytes, why did you make p an int* instead of
a char*?
>So then:
>only when using variable arguments, are arguments of type char (or short) placed on the stack as correspondingly promoted int.
Variadic arguments of rank less than int are promoted to int (or
unsigned int when necessary) before being passed. Assumptions about a
stack are extraneous.
--
Remove del for email
[toc] | [prev] | [next] | [standalone]
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2014-03-01 15:51 +0000 |
| Message-ID | <lesvmt$b8b$3@news.xmission.com> |
| In reply to | #41242 |
In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>,
Barry Schwarz <schwarzb@dqel.com> wrote:
...
>There is no requirement for the char to occupy sizeof(int) bytes on
>the stack.
Donning clc-pedant hat (which, admittedly, doesn't fit me very well):
There is no requirement for there to be a stack.
And, generally, you can get yourself into trouble with the Kiki-squad if
you use "the s-word" around here.
--
"That's the eternal flame."[7] The single became another worldwide hit.[8]
Hoffs was actually naked when she recorded the song, after being convinced
by Sigerson that Olivia Newton-John got her amazing performances by
recording everything while naked.[9]
(From: http://en.wikipedia.org/wiki/The_Bangles)
[toc] | [prev] | [next] | [standalone]
| From | Richard <rgrdev_@gmail.com> |
|---|---|
| Date | 2014-03-01 17:50 +0100 |
| Message-ID | <87k3cdx3qy.fsf@gmail.com> |
| In reply to | #41243 |
gazelle@shell.xmission.com (Kenny McCormack) writes: > In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>, > Barry Schwarz <schwarzb@dqel.com> wrote: > ... >>There is no requirement for the char to occupy sizeof(int) bytes on >>the stack. > > Donning clc-pedant hat (which, admittedly, doesn't fit me very well): > > There is no requirement for there to be a stack. > > And, generally, you can get yourself into trouble with the Kiki-squad if > you use "the s-word" around here. On the ball there. Well done. Kiki and co should be in to agree with you any moment now... -- "Avoid hyperbole at all costs, its the most destructive argument on the planet" - Mark McIntyre in comp.lang.c
[toc] | [prev] | [next] | [standalone]
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2014-03-01 18:36 +0000 |
| Message-ID | <let9bj$feu$1@news.xmission.com> |
| In reply to | #41245 |
In article <87k3cdx3qy.fsf@gmail.com>, Richard <rgrdev_@gmail.com> wrote: >gazelle@shell.xmission.com (Kenny McCormack) writes: > >> In article <ket3h95s1u740rqs3ldhrst3elqp377std@4ax.com>, >> Barry Schwarz <schwarzb@dqel.com> wrote: >> ... >>>There is no requirement for the char to occupy sizeof(int) bytes on >>>the stack. >> >> Donning clc-pedant hat (which, admittedly, doesn't fit me very well): >> >> There is no requirement for there to be a stack. >> >> And, generally, you can get yourself into trouble with the Kiki-squad if >> you use "the s-word" around here. > >On the ball there. Well done. Kiki and co should be in to agree with you >any moment now... And that is, after all, every CLC posters primary goal - to be acknowledged and accepted by Kiki and his coterie. It is certainly mine... -- Modern Christian: Someone who can take time out from complaining about "welfare mothers popping out babies we have to feed" to complain about welfare mothers getting abortions that PREVENT more babies to be raised at public expense.
[toc] | [prev] | [next] | [standalone]
| From | Melzzzzz <mel@zzzzz.invalid> |
|---|---|
| Date | 2014-03-01 11:22 +0100 |
| Message-ID | <lescdm$sl8$1@solani.org> |
| In reply to | #41226 |
On Sat, 1 Mar 2014 01:29:54 -0800 (PST)
jononanon@googlemail.com wrote:
> Hi there!
>
> Check this out -> the following code always works:
>
> printf("%d %d %d", (char)'\1', (short)2, 3);
> // prints: 1 2 3
>
> So a conversion specifier of %d works with type int, or "SMALLER"
> integer-types (short or char) !!!
>
> Why does this work??
Architecture/abi is that way.
> Is my explanation correct?
>
>
>
>
> ->
> With printf("%d", (char) '\1')
> the argument 1 lands on the stack not as char parameter, but as a
> parameter promoted to int, and the library code that handles the
> access to the parameter uses va_arg(ap, int) to access it. You can
> never use va_arg(ap, char) -> that would distroy a consistent
> handling of the stack-parameters!
On x86-64 first 6(Unix)/4(Windows) parameters are passed through
64 bit registers. Library code does use va_arg(ap,int)
but value is correct as accessing parts of 64 bit register
is correct. Same with 32 bit , but with stack of 32 bit
bit parameters. I guess that if parameter is long
long (in case of 32bit program) your logic breaks.
I'm not sure how long long is passed but it cannot
fit in 32 bit parameter, so either it has to be split
in two parameters or pointer to it is passed.
In any case I think that would break char/int parameters.
--
Click OK to continue...
[toc] | [prev] | [next] | [standalone]
| From | jononanon@googlemail.com |
|---|---|
| Date | 2014-03-01 02:39 -0800 |
| Message-ID | <3a554fb0-085c-475f-935c-e8552586fd75@googlegroups.com> |
| In reply to | #41231 |
On Saturday, March 1, 2014 11:22:45 AM UTC+1, Melzzzzz wrote:
> I'm not sure how long long is passed but it cannot
>
> fit in 32 bit parameter, so either it has to be split
>
> in two parameters or pointer to it is passed.
>
> In any case I think that would break char/int parameters.
Yes, true:
printf("%lld %lld %lld\n", 1, 2, 3); /* stuffs up, if sizeof(int) < sizeof(long long) */
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2014-03-01 19:44 -0800 |
| Message-ID | <87vbvxuuvk.fsf@mib.org> |
| In reply to | #41231 |
Melzzzzz <mel@zzzzz.invalid> writes:
> On Sat, 1 Mar 2014 01:29:54 -0800 (PST)
> jononanon@googlemail.com wrote:
>> Check this out -> the following code always works:
>>
>> printf("%d %d %d", (char)'\1', (short)2, 3);
>> // prints: 1 2 3
>>
>> So a conversion specifier of %d works with type int, or "SMALLER"
>> integer-types (short or char) !!!
>>
>> Why does this work??
>
> Architecture/abi is that way.
The architecture/abi has nothing to do with it, at least not
directly. The language standard specifies that short arguments are
converted to int in this context. It might happen to be easier
to implement on some architectures (and architectures, ABIs, and
language standards tend to be designed to work well together),
but the compiler has to make it work regardless.
[temporarily posting through aioe.org due to problems with
eternal-september.org]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2014-03-01 02:34 -0800 |
| Message-ID | <lniory438k.fsf@nuthaus.mib.org> |
| In reply to | #41226 |
jononanon@googlemail.com writes:
> Hi there!
>
> Check this out -> the following code always works:
>
> printf("%d %d %d", (char)'\1', (short)2, 3);
> // prints: 1 2 3
>
> So a conversion specifier of %d works with type int, or "SMALLER"
> integer-types (short or char) !!!
>
> Why does this work??
> Is my explanation correct?
[...]
N1570 (C11 draft) 6.5.2.2p7:
The ellipsis notation in a function prototype declarator causes
argument type conversion to stop after the last declared
parameter. The default argument promotions are performed on
trailing arguments.
The default argument promotions convert float to double, and any integer
type narrower than int is convert to int if int can represent all the
values of the type, otherwise to unsigned int. (The latter avoids
overflow when an unsigned short value is promoted and short and int are
the same size.)
That's why, among other things, there are no specific printf formats for
float or short.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jononanon@googlemail.com |
|---|---|
| Date | 2014-03-01 02:49 -0800 |
| Message-ID | <937c14b6-d3fa-4735-980f-fd173ccfeee3@googlegroups.com> |
| In reply to | #41233 |
On Saturday, March 1, 2014 11:34:03 AM UTC+1, Keith Thompson wrote: > any integer > > type narrower than int is convert to int if int can represent all the > > values of the type, otherwise to unsigned int. (The latter avoids > > overflow when an unsigned short value is promoted and short and int are > > the same size.) > Is this conversion to unsigned in really important? I mean in terms of overflow! -> who cares? Isn't solely the bit-pattern important?? Because: Even if conversion were ONLY to signed int, the result via va_arg(ap, int), or via va_arg(ap, unsigned int) is what is important. And that is not controlled by the default argument promotion, but instead by the printf-conversion-specifier. (Am I missing something?)
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2014-03-01 09:10 -0500 |
| Message-ID | <lespp0$cjp$1@dont-email.me> |
| In reply to | #41235 |
On 03/01/2014 05:49 AM, jononanon@googlemail.com wrote: > On Saturday, March 1, 2014 11:34:03 AM UTC+1, Keith Thompson wrote: >> any integer >> >> type narrower than int is convert to int if int can represent all the >> >> values of the type, otherwise to unsigned int. (The latter avoids >> >> overflow when an unsigned short value is promoted and short and int are >> >> the same size.) >> > Is this conversion to unsigned in really important? > I mean in terms of overflow! -> who cares? Isn't solely the bit-pattern important?? No - because there are real machines where overflow has bad consequences. > Because: Even if conversion were ONLY to signed int, the result via > va_arg(ap, int), or via va_arg(ap, unsigned int) is what is important. And that is not controlled by the default argument promotion, but instead by the printf-conversion-specifier. (Am I missing something?) If the type of the argument, after promotion, differs from the type that you specify in the corresponding invocation of va_arg(), the behavior is undefined - such code might work, but you shouldn't count on it. When it's just the difference between a given signed type and the corresponding unsigned type, it's fairly safe, so long as only positive values are involved: such are guaranteed to have the same representation both types. No such guarantee applies to int and unsigned short, even if they both have the same size - in principle, at least, a fully conforming implementation could, for example, have big-endian int, and little-endian unsigned short. In this particular case, you can probably get away with sloppy coding that ignores these issues - but it's better to handle it correctly. If there's a possibility that a given value that is subject to the default promotions might promote to either int or unsigned int, depending upon the characteristics of the implementation you're using, you should write your code to either remove that possibility, or deal with it. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | <william@wilbur.25thandClement.com> |
|---|---|
| Date | 2014-03-01 15:38 -0800 |
| Message-ID | <el7aua-9bg.ln1@wilbur.25thandClement.com> |
| In reply to | #41233 |
Keith Thompson <kst-u@mib.org> wrote:
> jononanon@googlemail.com writes:
>> Hi there!
>>
>> Check this out -> the following code always works:
>>
>> printf("%d %d %d", (char)'\1', (short)2, 3);
>> // prints: 1 2 3
>>
>> So a conversion specifier of %d works with type int, or "SMALLER"
>> integer-types (short or char) !!!
>>
>> Why does this work??
>> Is my explanation correct?
> [...]
>
> N1570 (C11 draft) 6.5.2.2p7:
>
> The ellipsis notation in a function prototype declarator causes
> argument type conversion to stop after the last declared
> parameter. The default argument promotions are performed on
> trailing arguments.
>
> The default argument promotions convert float to double, and any integer
> type narrower than int is convert to int if int can represent all the
> values of the type, otherwise to unsigned int. (The latter avoids
> overflow when an unsigned short value is promoted and short and int are
> the same size.)
>
> That's why, among other things, there are no specific printf formats for
> float or short.
There's the `h' length modifier for shorts. Also `hh' for chars.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2014-03-01 19:47 -0800 |
| Message-ID | <87r46luuqw.fsf@mib.org> |
| In reply to | #41266 |
<william@wilbur.25thandClement.com> writes:
> Keith Thompson <kst-u@mib.org> wrote:
[...]
>> The default argument promotions convert float to double, and any
>> integer type narrower than int is convert to int if int can represent
>> all the values of the type, otherwise to unsigned int. (The latter
>> avoids overflow when an unsigned short value is promoted and short
>> and int are the same size.)
>>
>> That's why, among other things, there are no specific printf formats
>> for float or short.
>
> There's the `h' length modifier for shorts. Also `hh' for chars.
Good point, I momentarily forgot about those.
"%hd" still requires an int argument (possibly promoted from short),
but the value is *converted* to short before printing. I'm actually
not sure what it's good for. If the argument is already in the
range of type short, then it behaves identically to "%d"; if it's
outside that range, the result is implementation-defined (or, at
least in principle, it can raise an implementation-defined signal).
At least for "%hu" or "%hx", the behavior of the conversion is well
defined, but the behavior is still identical to "%u" or "%x" if the
argument is of type unsigned short. But I'm really not sure why the "h"
and "hh" length modifiers were added to the language. ("h" was added in
ANSI C89, "hh" in C99.)
[temporarily posting through aioe.org due to problems with
eternal-september.org]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | <william@wilbur.25thandClement.com> |
|---|---|
| Date | 2014-03-01 21:12 -0800 |
| Message-ID | <97raua-i3l.ln1@wilbur.25thandClement.com> |
| In reply to | #41275 |
Keith Thompson <kst-u@mib.org> wrote: > <william@wilbur.25thandClement.com> writes: >> Keith Thompson <kst-u@mib.org> wrote: > [...] >>> The default argument promotions convert float to double, and any >>> integer type narrower than int is convert to int if int can represent >>> all the values of the type, otherwise to unsigned int. (The latter >>> avoids overflow when an unsigned short value is promoted and short >>> and int are the same size.) >>> >>> That's why, among other things, there are no specific printf formats >>> for float or short. >> >> There's the `h' length modifier for shorts. Also `hh' for chars. > > Good point, I momentarily forgot about those. > > "%hd" still requires an int argument (possibly promoted from short), > but the value is *converted* to short before printing. I'm actually > not sure what it's good for. If the argument is already in the > range of type short, then it behaves identically to "%d"; if it's > outside that range, the result is implementation-defined (or, at > least in principle, it can raise an implementation-defined signal). I submitted a bug report to Apple for an issue related to %hu, which they dutifully fixed in a subsequent release. Their version of the ntohs() routine, because of their use of a ternary operator, resulted in an expression of int type, rather than the documented uint16_t. The original code looked like ((__builtin_constant_p(x) ? __DARWIN_OSSwapConstInt16(x) : _OSSwapInt16(x))) The fix was to cast the result. See /usr/include/libkern/_OSByteOrder.h. GCC's printf checker never caught this issue. The type was ultimately promoted to int, anyhow, so using %hu with an int parameter was inconsequential. clang, however, wasn't as forgiving. I began using upstream clang before Apple swapped in clang for their GCC frontend, and apparently was one of the first people to spot this issue. (Or maybe just the first one to care.) One could quibble whether GCC should have complained or whether clang should have remained silent. But I choose to file the bug with Apple and not clang. Note: On recent OS X verions /usr/bin/gcc is a tweaked version of clang, so merely invoking `gcc' will still result in warnings. gcc 4.8's printf checker still accepts int expressions for %hd without a diagnostic.
[toc] | [prev] | [next] | [standalone]
| From | Joe Pfeiffer <pfeiffer@cs.nmsu.edu> |
|---|---|
| Date | 2014-03-02 07:47 -0700 |
| Message-ID | <1bk3cc4pzt.fsf@snowball.wb.pfeifferfamily.net> |
| In reply to | #41275 |
Keith Thompson <kst-u@mib.org> writes:
> <william@wilbur.25thandClement.com> writes:
>> Keith Thompson <kst-u@mib.org> wrote:
> [...]
>>> The default argument promotions convert float to double, and any
>>> integer type narrower than int is convert to int if int can represent
>>> all the values of the type, otherwise to unsigned int. (The latter
>>> avoids overflow when an unsigned short value is promoted and short
>>> and int are the same size.)
>>>
>>> That's why, among other things, there are no specific printf formats
>>> for float or short.
>>
>> There's the `h' length modifier for shorts. Also `hh' for chars.
>
> Good point, I momentarily forgot about those.
>
> "%hd" still requires an int argument (possibly promoted from short),
> but the value is *converted* to short before printing. I'm actually
> not sure what it's good for. If the argument is already in the
> range of type short, then it behaves identically to "%d"; if it's
> outside that range, the result is implementation-defined (or, at
> least in principle, it can raise an implementation-defined signal).
I always assumed that it was for consistency with scanf.
> At least for "%hu" or "%hx", the behavior of the conversion is well
> defined, but the behavior is still identical to "%u" or "%x" if the
> argument is of type unsigned short. But I'm really not sure why the "h"
> and "hh" length modifiers were added to the language. ("h" was added in
> ANSI C89, "hh" in C99.)
>
> [temporarily posting through aioe.org due to problems with
> eternal-september.org]
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-03-02 20:53 +0000 |
| Message-ID | <20140302125139.273@kylheku.com> |
| In reply to | #41292 |
On 2014-03-02, Joe Pfeiffer <pfeiffer@cs.nmsu.edu> wrote:
> Keith Thompson <kst-u@mib.org> writes:
>
>> <william@wilbur.25thandClement.com> writes:
>>> Keith Thompson <kst-u@mib.org> wrote:
>> [...]
>>>> The default argument promotions convert float to double, and any
>>>> integer type narrower than int is convert to int if int can represent
>>>> all the values of the type, otherwise to unsigned int. (The latter
>>>> avoids overflow when an unsigned short value is promoted and short
>>>> and int are the same size.)
>>>>
>>>> That's why, among other things, there are no specific printf formats
>>>> for float or short.
>>>
>>> There's the `h' length modifier for shorts. Also `hh' for chars.
>>
>> Good point, I momentarily forgot about those.
>>
>> "%hd" still requires an int argument (possibly promoted from short),
>> but the value is *converted* to short before printing. I'm actually
>> not sure what it's good for. If the argument is already in the
>> range of type short, then it behaves identically to "%d"; if it's
>> outside that range, the result is implementation-defined (or, at
>> least in principle, it can raise an implementation-defined signal).
>
> I always assumed that it was for consistency with scanf.
There are blatant inconsistencies like:
printf("%f", double_var);
scanf("%f", &double_var); /* error */
scanf("%lf", &double_var); /* correct */
The consistency ship sailed long ago; printf and scanf missed it.
[toc] | [prev] | [next] | [standalone]
| From | jgk@panix.com (Joe keane) |
|---|---|
| Date | 2014-03-04 00:23 +0000 |
| Message-ID | <lf36ej$rg5$1@reader1.panix.com> |
| In reply to | #41309 |
In article <20140302125139.273@kylheku.com>,
Kaz Kylheku <kaz@kylheku.com> wrote:
>There are blatant inconsistencies like:
>
> printf("%f", double_var);
>
> scanf("%f", &double_var); /* error */
>
> scanf("%lf", &double_var); /* correct */
First one should be "lf" ('long float').
When calling a varargs function it is legal to pass 'float' where
'double' is expected and vice versa.
A lot of rules for 'float' were changed, just not this one.
So there is your problem.
The 'printf' side has always been more tolerant; screwing up a 'scanf'
format will quickly crash, if you're lucky...
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-03-04 00:33 +0000 |
| Message-ID | <20140303162419.577@kylheku.com> |
| In reply to | #41338 |
On 2014-03-04, Joe keane <jgk@panix.com> wrote:
> In article <20140302125139.273@kylheku.com>,
> Kaz Kylheku <kaz@kylheku.com> wrote:
>>There are blatant inconsistencies like:
>>
>> printf("%f", double_var);
>>
>> scanf("%f", &double_var); /* error */
>>
>> scanf("%lf", &double_var); /* correct */
>
> First one should be "lf" ('long float').
Nope. %f takes double.
"f,F A double argument representing a floating-point number is converted to
decimal notation in the style [−]ddd.ddd, where the number of digits after
the decimal-point character is equal to the precision specification."
(ISO/IEC 9899:1999)
Where is %g and %e in scanf? If printf were consistent with scanf,
%g would scan the general printed representation that may use exponents
or not, %f would scan only [-]ddd.ddd, and %e only exponentials.
%f in printf perhaps doesn't stand for "floating". It means "fixed digits":
in a sense the opposite of a "floating" decimal point with an exponent.
> When calling a varargs function it is legal to pass 'float' where
> 'double' is expected and vice versa.
When calling a varargs function, it is impossible to pass a float;
any such expression widens to a double.
> A lot of rules for 'float' were changed, just not this one.
Recently? In what way?
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web