Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > va_arg and short

Reply
Thread Tools

va_arg and short

 
 
Glen Herrmannsfeldt
Guest
Posts: n/a
 
      11-02-2003
I was compiling a program written by someone else about six years ago, and
widely distributed at the time. It also includes makefiles for many
different systems, so I know it has been compiled with many different
compilers.

I got compile errors when it used va_arg to fetch an argument of type short.
That seemed a little strange to me, so I changed it to int and it compiled
just fine.

So now I wonder, just what is the rule for va_arg and short? It would seem
strange to reject certain types, yet that is what the compiler did.

-- glen


 
Reply With Quote
 
 
 
 
Chris Torek
Guest
Posts: n/a
 
      11-02-2003
In article <aE0pb.81932$HS4.680953@attbi_s01>
Glen Herrmannsfeldt <(E-Mail Removed)> writes:
>I got compile errors when [some code] used va_arg to fetch an
>argument of type short. That seemed a little strange to me, so
>I changed it to int and it compiled just fine.
>
>So now I wonder, just what is the rule for va_arg and short?


It is up to the programmer to avoid passing "narrow" types to the
va_arg() macro.

The type name given to va_arg() must match the type of the actual
parameter, whatever it was. In a call to a function that lacks a
prototype, or whose prototype ends in ", ..." (where the actual
argument matches the ", ..." part), the compiler is obligated to
perform the "default argument promotions". These replace (signed)
char and short with int, and float with double. They also replace
unsigned char and unsigned short with some wider type, but the
wider type is not easily predicted because the ANSI X3J11 committee
folks chose the wrong rules in 1985 or so. (Plain char will widen
to signed int on any sensible platform, but even this is not
guaranteed.)

Hence, for strict conformance, one might code something like this:

case 'i': /* obtain an int */
int_val = va_arg(ap, int);
...
break;

case 's': /* obtain a (signed) short */
short_val = (short)va_arg(ap, int);
...
break;

case 'S': /* obtain an unsigned short */
#if USHRT_MAX > INT_MAX
ushort_val = (unsigned short)va_arg(ap, unsigned int);
#else
ushort_val = (unsigned short)va_arg(ap, int);
#endif
...
break;

Note the icky need for a "#if" test, to tell which type unsigned
short becomes under the default argument promotions. (Had C used
the "predictably surprising" rule "unsigned promotes to unsigned",
the #if would not be required. Of course, this rule would also
have to go with one that says that if plain char is unsigned, it
widens to signed int anyway, possibly with a secondary requirement
for UCHAR_MAX to be no greater than INT_MAX on any such system.
This would not have been a hardship for existing implementations,
and the resulting rules are far easier to work with and do not
change from one implementation to another the way the current ones
do.)

>It would seem strange to reject certain types, yet that is what
>the compiler did.


A C compiler is not required to detect and reject such usage -- it
falls under the broad umbrella of undefined behavior -- but a kind
and clever compiler will do it.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
 
 
 
James Hu
Guest
Posts: n/a
 
      11-02-2003
On 2003-11-02, Glen Herrmannsfeldt <(E-Mail Removed)> wrote:
> I was compiling a program written by someone else about six years ago, and
> widely distributed at the time. It also includes makefiles for many
> different systems, so I know it has been compiled with many different
> compilers.
>
> I got compile errors when it used va_arg to fetch an argument of type short.
> That seemed a little strange to me, so I changed it to int and it compiled
> just fine.
>
> So now I wonder, just what is the rule for va_arg and short? It would seem
> strange to reject certain types, yet that is what the compiler did.


C99: 6.3.1.1, paragraph 2

"If an int can represent all the values of the original type, the
value is converted to an int; otherwise, it is converted to an
unsigned int. These are called the /integer promotions/."

C99: 6.5.2.2, paragraph 6

"If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed
on each argument, and arguments that have type float are promoted
to double. These are called the /default argument promotions/.

C99: 6.5.2.2, paragraph 7

"The ellipses 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."


-- James
 
Reply With Quote
 
Glen Herrmannsfeldt
Guest
Posts: n/a
 
      11-02-2003

"Chris Torek" <(E-Mail Removed)> wrote in message
news:bo27at$10g$(E-Mail Removed)...
> In article <aE0pb.81932$HS4.680953@attbi_s01>
> Glen Herrmannsfeldt <(E-Mail Removed)> writes:
> >I got compile errors when [some code] used va_arg to fetch an
> >argument of type short. That seemed a little strange to me, so
> >I changed it to int and it compiled just fine.
> >
> >So now I wonder, just what is the rule for va_arg and short?

>
> It is up to the programmer to avoid passing "narrow" types to the
> va_arg() macro.
>
> The type name given to va_arg() must match the type of the actual
> parameter, whatever it was. In a call to a function that lacks a
> prototype, or whose prototype ends in ", ..." (where the actual
> argument matches the ", ..." part), the compiler is obligated to
> perform the "default argument promotions". These replace (signed)
> char and short with int, and float with double. They also replace
> unsigned char and unsigned short with some wider type, but the
> wider type is not easily predicted because the ANSI X3J11 committee
> folks chose the wrong rules in 1985 or so. (Plain char will widen
> to signed int on any sensible platform, but even this is not
> guaranteed.)


I knew about the default promotions, so it wasn't hard to know what to
change it to. The program was so widely distributed, and run on so many
different compilers, I was surprised that it hadn't been seen before. Now,
most likely it is never executed. It is a modified version of sprintf(),
and if the h flag is used it will print a short. I don't know anyone that
ever did that, though they may have been surprised if they did.

(snip)

> A C compiler is not required to detect and reject such usage -- it
> falls under the broad umbrella of undefined behavior -- but a kind
> and clever compiler will do it.


Apparently compilers have gotten kinder and cleverer in recent years.

-- glen


 
Reply With Quote
 
Christian Bau
Guest
Posts: n/a
 
      11-02-2003
In article <aE0pb.81932$HS4.680953@attbi_s01>,
"Glen Herrmannsfeldt" <(E-Mail Removed)> wrote:

> I was compiling a program written by someone else about six years ago, and
> widely distributed at the time. It also includes makefiles for many
> different systems, so I know it has been compiled with many different
> compilers.
>
> I got compile errors when it used va_arg to fetch an argument of type short.
> That seemed a little strange to me, so I changed it to int and it compiled
> just fine.
>
> So now I wonder, just what is the rule for va_arg and short? It would seem
> strange to reject certain types, yet that is what the compiler did.


When you use the va_arg macro, the type that you supply must (with some
exceptions that don't apply here) match the type of the actual argument
_after default promotions_.

Any argument of type short would be promoted to int, so using short in
the va_arg macro can never match the type of the actual argument after
default promotions.
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      11-03-2003
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <(E-Mail Removed)> wrote in message news:<aE0pb.81932$HS4.680953@attbi_s01>...
> I was compiling a program written by someone else about six years ago, and
> widely distributed at the time. It also includes makefiles for many
> different systems, so I know it has been compiled with many different
> compilers.
>
> I got compile errors when it used va_arg to fetch an argument of type short.
> That seemed a little strange to me, so I changed it to int and it compiled
> just fine.
>
> So now I wonder, just what is the rule for va_arg and short? It would seem
> strange to reject certain types, yet that is what the compiler did.


I wonder why va_arg could not accept a type subject to promotion and
handle them accordingly, i.e. accept the promoted type implicitly and
convert it to the original/requested type. [So, cases like the
character types and unsigned short, which might promote to signed or
unsigned int, could be handled without having to resort to integer
limit checks.]

What sorts of architectures would make such an alternative va_arg
behaviour difficult to implement in practice?

[I appreciate the status quo is not likely to change, I'm just curious
as to whether it was considered for C90 or C99, or if not, how the
Committee might discus the request.]

--
Peter
 
Reply With Quote
 
Gordon Burditt
Guest
Posts: n/a
 
      11-03-2003
>I wonder why va_arg could not accept a type subject to promotion and
>handle them accordingly, i.e. accept the promoted type implicitly and
>convert it to the original/requested type. [So, cases like the
>character types and unsigned short, which might promote to signed or
>unsigned int, could be handled without having to resort to integer
>limit checks.]
>
>What sorts of architectures would make such an alternative va_arg
>behaviour difficult to implement in practice?


If C had type-valued functions, this might be easier to deal with.
For example,
type_standard_promotions(typeof(short)) == typeof(int)
I don't think clever tricks with macros can deal with this without
also using a magic compiler built-in.

As it stands, the second argument of va_arg has to be a valid type
if you append a "*" to it; this restriction wouldn't be necessary
if you had:
type_addressof(typeof(int)) == typeof(int *)

>[I appreciate the status quo is not likely to change, I'm just curious
>as to whether it was considered for C90 or C99, or if not, how the
>Committee might discus the request.]


Gordon L. Burditt
 
Reply With Quote
 
Christian Bau
Guest
Posts: n/a
 
      11-03-2003
In article <(E-Mail Removed) >,
http://www.velocityreviews.com/forums/(E-Mail Removed) (Peter Nilsson) wrote:

> [Cross posted to comp.std.c.]
>
> "Glen Herrmannsfeldt" <(E-Mail Removed)> wrote in message
> news:<aE0pb.81932$HS4.680953@attbi_s01>...
> > I was compiling a program written by someone else about six years ago, and
> > widely distributed at the time. It also includes makefiles for many
> > different systems, so I know it has been compiled with many different
> > compilers.
> >
> > I got compile errors when it used va_arg to fetch an argument of type
> > short.
> > That seemed a little strange to me, so I changed it to int and it compiled
> > just fine.
> >
> > So now I wonder, just what is the rule for va_arg and short? It would
> > seem
> > strange to reject certain types, yet that is what the compiler did.

>
> I wonder why va_arg could not accept a type subject to promotion and
> handle them accordingly, i.e. accept the promoted type implicitly and
> convert it to the original/requested type. [So, cases like the
> character types and unsigned short, which might promote to signed or
> unsigned int, could be handled without having to resort to integer
> limit checks.]


These are no problem anyway, because the C Standard explicitely allows
you to use for example unsigned int instead of int if the value passed
can be represented in both types. So whether unsigned short is passed as
int or unsigned int, you can always read it as an unsigned int.

> What sorts of architectures would make such an alternative va_arg
> behaviour difficult to implement in practice?


Many implementations implement va_arg as a macro, without requiring any
special knowledge in the compiler itself. Producing code that works for
"short" if sizeof (short) < sizeof (int) by using a macro alone is
difficult. So this requirement would mean you have to change the
compiler.

On the other hand, as a compiler writer I would say that the best
possible result is a compile time error. That way the programmer has a
chance to change their code. Much better than accepting code that will
be accepted and lead to a crash on the next machine.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-03-2003
(E-Mail Removed) (Peter Nilsson) wrote in message news:<(E-Mail Removed). com>...
> [Cross posted to comp.std.c.]
>
> "Glen Herrmannsfeldt" <(E-Mail Removed)> wrote in message news:<aE0pb.81932$HS4.680953@attbi_s01>...
> > I was compiling a program written by someone else about six years ago, and
> > widely distributed at the time. It also includes makefiles for many
> > different systems, so I know it has been compiled with many different
> > compilers.
> >
> > I got compile errors when it used va_arg to fetch an argument of type short.
> > That seemed a little strange to me, so I changed it to int and it compiled
> > just fine.
> >
> > So now I wonder, just what is the rule for va_arg and short? It would seem
> > strange to reject certain types, yet that is what the compiler did.

>
> I wonder why va_arg could not accept a type subject to promotion and
> handle them accordingly, i.e. accept the promoted type implicitly and
> convert it to the original/requested type. [So, cases like the
> character types and unsigned short, which might promote to signed or
> unsigned int, could be handled without having to resort to integer
> limit checks.]
>
> What sorts of architectures would make such an alternative va_arg
> behaviour difficult to implement in practice?


The normal va_arg() macro can, on many platforms, expand to normal C
code. On some platforms, something like the following is sufficient:

typedef char* va_list;
#define va_start(arg) )(&arg+sizeof(arg))
#define va_arg(ap,type) ((type*)(ap+=sizeof(type)))[-1]
#define va_end(ap)

Try to figure out how to modify that without using any extensions to C
such as sizeof(promoted_typeof(type)). An implementation is free, of
course, to use extensions, but I think that the committee would resist
changing the specification in a way that would make the use of an
extension mandatory.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-03-2003
Christian Bau <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
....
> Many implementations implement va_arg as a macro, ...


I should hope so! The standard requires that it be a macro.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Difference of extern short *x and extern short x[]? Andre C Programming 5 07-17-2012 07:38 PM
va_arg... recursion: changing arguments and the using recursion jononanon@googlemail.com C Programming 8 04-26-2012 08:37 PM
Re: va_arg() question Eric Sosman C Programming 1 08-08-2003 12:25 AM
Re: va_arg() question Gordon Burditt C Programming 0 08-07-2003 04:19 PM
variable num args via 'va_arg' Suzanne Vogel C++ 2 07-05-2003 02:19 PM



Advertisments