Velocity Reviews - Computer Hardware Reviews

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

Reply
Thread Tools

va_arg and short

 
 
Thad Smith
Guest
Posts: n/a
 
      11-03-2003
Peter Nilsson wrote:

> 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.]


While the programmer should know that the type char and short are
promoted, what about int32_t? Can it be an argument of va_arg? It
might be equivalent to a short (needing promotion), or a int or a long.
Is there any way of portably accessing a variadic int32_t (or intX_t for
X >= 16) parameter?

Thad
 
Reply With Quote
 
 
 
 
Dan Pop
Guest
Posts: n/a
 
      11-03-2003
In <aE0pb.81932$HS4.680953@attbi_s01> "Glen Herrmannsfeldt" <(E-Mail Removed)> writes:

>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.


It's a clear case of undefined behaviour:

The va_arg macro expands to an expression that has the type and
value of the next argument in the call. The parameter ap shall be the
same as the va_list ap initialized by va_start. Each invocation of
va_arg modifies ap so that the values of successive arguments are
returned in turn. The parameter type is a type name specified such
that the type of a pointer to an object that has the specified type
can be obtained simply by postfixing a * to type. If there is no
actual next argument, or if type is not compatible with the type of
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the actual next argument (as promoted according to the default
^^^^^^^^^^^^^^^^^^^^^^^^^========================= ============
argument promotions), the behavior is undefined.
====================^^^^^^^^^^^^^^^^^^^^^^^^^^^

A short argument is promoted to int, therefore, by specifying short as the
type you're guaranteed to have a type mismatch, leading to undefined
behaviour. The compiler that rejected it just did you a favour. The code
was written by an incompetent programmer.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
 
Glen Herrmannsfeldt
Guest
Posts: n/a
 
      11-04-2003

"Dan Pop" <(E-Mail Removed)> wrote in message
news:bo64s4$dkd$(E-Mail Removed)...
> In <aE0pb.81932$HS4.680953@attbi_s01> "Glen Herrmannsfeldt"

<(E-Mail Removed)> writes:
>
> >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.


(snip)

> A short argument is promoted to int, therefore, by specifying short as the
> type you're guaranteed to have a type mismatch, leading to undefined
> behaviour. The compiler that rejected it just did you a favour. The code
> was written by an incompetent programmer.


I don't disagree with that. This program is part of a widely distributed
program library, and I am sure has been compiled on many compilers over the
years. Most likely, this statement has never been executed, so it really
doesn't matter what it compiles into. The problem comes when a program is
supposed to be portable to a wide variety of machines and compilers, with
the expectation that it can be compiled and installed by non-C programmers.
Someone is supposed to be able to untar it, run make, and not have any
compiler or link errors. Considering that it passed so many compilers on
the way, would it have been reasonable to make it a warning?

The next error I ran into, in a different library, came from not finding the
include file ndbm.h. It seems that it is now db.h, at least on the system
that I was using.

Oh well.

-- glen


 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      11-04-2003
(E-Mail Removed) (James Kuyper) wrote in message news:<(E-Mail Removed). com>...
> (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_start(ap,arg) ((ap) = (char *) &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.


The 'extension' is static type analysis, indeed, the *same* analysis
used to promote parameters in variadic function calls in the first
place.

--
Peter
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      11-04-2003
Thad Smith <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> Peter Nilsson wrote:
>
> > 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.]

>
> While the programmer should know that the type char and short are
> promoted, what about int32_t? Can it be an argument of va_arg? It
> might be equivalent to a short (needing promotion), or a int or a long.
> Is there any way of portably accessing a variadic int32_t (or intX_t for
> X >= 16) parameter?


A tedious one...

#if INT32_MAX <= INT_MAX
int32_t x = va_arg(ap, int);
#else
int32_t x = va_arg(ap, int32_t);
#endif

--
Peter
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      11-04-2003
>(E-Mail Removed) (James Kuyper) wrote in message news:<(E-Mail Removed). com>...
>> 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))


In article <(E-Mail Removed) >
Peter Nilsson <(E-Mail Removed)> writes:
> #define va_start(ap,arg) ((ap) = (char *) &arg) /* ? */


No -- the idea is to take the address of the "variable" named "..."
in something like:

void f(const char *fmt, ...) {
va_list ap;

va_start(ap, fmt);
/* code here */
va_end(ap);
}

>> #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)). ...


>The 'extension' is static type analysis, indeed, the *same* analysis
>used to promote parameters in variadic function calls in the first
>place.


Yes, but while this is available to the compiler (internally),
there is no existing C construct that requires that it be exposed
to the programmer. A __sizeof_promoted_type operator *ought* to
be trivial to add (because the compiler has to know how to do this
inside), but it does have to be added. (It is slightly worse than
this; see the end of this article.)

All that said, back in 1989, the X3J11 committee actually changed
the way one used what was then <varargs.h>, adding some required
explicit syntax -- the ", ..." part of a prototype -- and changing
the va_start() macro so that it takes two arguments instead of one.
Having done that, I always thought it was silly not to go the rest
of the way, and make "..." act like a special purpose variable:

#define va_start(ap) ((ap) = &...)

While va_start() could be retained (from <varargs.h> in the new
<stdarg.h>), the C committee could have written that this is the
one and only correct way to #define it. The "variable" named ...
would thus become a non-modifiable, indescribably-typed lvalue
whose only allowed operation is "take its address", producing a
value of whatever type "va_list" is.

Note that this -- removing the second argument to va_start() --
neatly expresses the constraint C imposes, that there only be a
single set of varying arguments. Having that second argument
implies (inappropriately) that one might be able to start the
varying portion at different points. Furthermore, with this "&..."
change, the requirement for at least one fixed argument could also
be dropped, giving us the syntax:

void g(...) {
va_list ap;

ap = &...; /* inline expansion of va_start(ap) */
/* code here */
va_end(ap);
}

This kind of function makes sense in some contexts, e.g., when
the body is something like:

char *p, *ret;
size_t len = 0;

while ((p = va_arg(ap, char *)) != NULL)
len += strlen(p);
va_end(ap);
ret = malloc(len + 1);
if (ret != NULL) {
char *tail = ret;

va_start(ap);
while ((p = va_arg(ap, char *)) != NULL) {
/* can do this in one line with sprintf, but is slow */
strcpy(tail, p);
tail += strlen(tail);
}
va_end(ap);
*tail = '\0'; /* in case there are no strings */
}

and of course a final "return ret".

The issue of whether to require promoted types to va_arg() could
remain separate. Requiring implementations to provide a "size of
promoted type" keyword, on implementations that use something as
simple as the va_arg() macro described above, is not much of a
hardship -- and for implementations that use "secret" compiler
tricks to access the varying arguments, doing the promotion is
still not a hardship. I for one think it would be an improvement:
not necessarily an *important* one, but in some ways, a "good"
language is one in which all the minor irritants have been removed
wherever feasible. One of J&W Pascal's original nasty failings
was the lack of a default case. Yes, you can work around it with
an "if" in front of the switch/case -- but this is a pesky thorn,
and there is no reason not to remove it from the lion's foot.

Assuming we *were* to add a special new keyword or two, here is
one way might rewrite va_arg:

/* original:
va_arg(ap, ty) (((ty *)(ap += sizeof(ty)))[-1])
new: */
#define va_arg(ap, ty) ((ty)((__convert_to_ptr_to_promoted(ty, \
ap += __sizeof_promoted(ty)))[-1]))

This also removes the pesky thorn that the "type" parameter to
va_arg be syntactically valid after suffixing with "*".
--
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
 
Brian Inglis
Guest
Posts: n/a
 
      11-04-2003
On Mon, 03 Nov 2003 10:17:18 -0700 in comp.std.c, Thad Smith
<(E-Mail Removed)> wrote:

>Peter Nilsson wrote:
>
>> 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.]

>
>While the programmer should know that the type char and short are
>promoted, what about int32_t? Can it be an argument of va_arg? It
>might be equivalent to a short (needing promotion), or a int or a long.
>Is there any way of portably accessing a variadic int32_t (or intX_t for
>X >= 16) parameter?


A long is guaranteed to hold at least the same values as an
int32_t, int and short may not. A short is guaranteed to hold at
least the same values as an int16_t. A signed char is guaranteed
to hold at least the same values as an int8_t. There are no other
guarantees AFAIR.

Thanks. Take care, Brian Inglis Calgary, Alberta, Canada
--
(E-Mail Removed) (Brian dot Inglis at SystematicSw dot ab dot ca)
fake address use address above to reply
 
Reply With Quote
 
Fergus Henderson
Guest
Posts: n/a
 
      11-04-2003
(E-Mail Removed) (Peter Nilsson) writes:

>Thad Smith <(E-Mail Removed)> wrote:
>> Is there any way of portably accessing a variadic int32_t (or intX_t for
>> X >= 16) parameter?

>
>A tedious one...
>
> #if INT32_MAX <= INT_MAX
> int32_t x = va_arg(ap, int);
> #else
> int32_t x = va_arg(ap, int32_t);
> #endif


Well, if that works, you could do it a little less tediously:

#define promoted_va_arg(ap, type, max) \
((max) <= INT_MAX ? va_arg((ap), int) : va_arg((ap), (type)))

int32_t x = promoted_va_arg(ap, int32_t, INT32_MAX);

--
Fergus Henderson <(E-Mail Removed)> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
 
Reply With Quote
 
Dan Pop
Guest
Posts: n/a
 
      11-04-2003
In <(E-Mail Removed)> Thad Smith <(E-Mail Removed)> writes:

>Peter Nilsson wrote:
>
>> 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.]

>
>While the programmer should know that the type char and short are
>promoted, what about int32_t? Can it be an argument of va_arg? It
>might be equivalent to a short (needing promotion), or a int or a long.
>Is there any way of portably accessing a variadic int32_t (or intX_t for
>X >= 16) parameter?


It is precisely this kind of issues that render the typedef'ed "types" a
lot less useful and easy to use than their fans believe.

If I multiply two size_t values, do I get undefined behaviour in case of
overflow or the result modulo SIZE_MAX? It depends on whether size_t is
subject to the integral promotions or not, an issue the standard is
not addressing at all.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: (E-Mail Removed)
 
Reply With Quote
 
Dan Pop
Guest
Posts: n/a
 
      11-04-2003
In <DJCpb.99053$Fm2.81929@attbi_s04> "Glen Herrmannsfeldt" <(E-Mail Removed)> writes:

>I don't disagree with that. This program is part of a widely distributed
>program library, and I am sure has been compiled on many compilers over the
>years. Most likely, this statement has never been executed, so it really
>doesn't matter what it compiles into. The problem comes when a program is
>supposed to be portable to a wide variety of machines and compilers, with
>the expectation that it can be compiled and installed by non-C programmers.


A non-C programmer has no business using a C compiler or building and
installing C programs. Imagine that the compiler emits a warning
(something that the person who wrote the code cannot avoid, for *any* C
compiler). Without knowing C, how can you tell if the problem can be
safely ignored, or the resulting executable should not be used?

>Someone is supposed to be able to untar it, run make, and not have any
>compiler or link errors.


Even required diagnostics can be produced as "warnings" instead of
"errors", so the absence of compiler errors means exactly nothing.

>Considering that it passed so many compilers on
>the way, would it have been reasonable to make it a warning?


When the code is obviously broken, an error is much better. Far too many
people blissfully ignore the warnings...

>The next error I ran into, in a different library, came from not finding the
>include file ndbm.h. It seems that it is now db.h, at least on the system
>that I was using.


Another argument for having a C programmer building C programs. Similar
issues arise with -lcurses vs -lncurses at link time. Again obvious for
the C programmer and totally insurmountable for the non-C programmer.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: (E-Mail Removed)
 
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