473,320 Members | 2,020 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

va_arg and short

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
Nov 13 '05 #1
99 8920
On 2003-11-02, Glen Herrmannsfeldt <ga*@ugcs.caltech.edu> 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
Nov 13 '05 #2
In article <aE0pb.81932$HS4.680953@attbi_s01>
Glen Herrmannsfeldt <ga*@ugcs.caltech.edu> 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 (40°39.22'N, 111°50.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.
Nov 13 '05 #3

"Chris Torek" <no****@elf.eng.bsdi.com> wrote in message
news:bo**********@elf.eng.bsdi.com...
In article <aE0pb.81932$HS4.680953@attbi_s01>
Glen Herrmannsfeldt <ga*@ugcs.caltech.edu> 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
Nov 13 '05 #4
In article <aE0pb.81932$HS4.680953@attbi_s01>,
"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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.
Nov 13 '05 #5
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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
Nov 13 '05 #6
>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
Nov 13 '05 #7
In article <63**************************@posting.google.com >,
ai***@acay.com.au (Peter Nilsson) wrote:
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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.
Nov 13 '05 #8
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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.
Nov 13 '05 #9
Christian Bau <ch***********@cbau.freeserve.co.uk> wrote in message news:<ch*********************************@slb-newsm1.svr.pol.co.uk>...
....
Many implementations implement va_arg as a macro, ...


I should hope so! The standard requires that it be a macro.
Nov 13 '05 #10
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
Nov 13 '05 #11
In <aE0pb.81932$HS4.680953@attbi_s01> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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: Da*****@ifh.de
Nov 13 '05 #12

"Dan Pop" <Da*****@cern.ch> wrote in message
news:bo***********@sunnews.cern.ch...
In <aE0pb.81932$HS4.680953@attbi_s01> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> writes:
I was compiling a program written by someone else about six years ago, andwidely 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 compiledjust 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
Nov 13 '05 #13
ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. com>...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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
Nov 13 '05 #14
Thad Smith <th*******@acm.org> wrote in message news:<3F***************@acm.org>...
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
Nov 13 '05 #15
On Mon, 03 Nov 2003 10:17:18 -0700 in comp.std.c, Thad Smith
<th*******@acm.org> 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
--
Br**********@CSi.com (Brian dot Inglis at SystematicSw dot ab dot ca)
fake address use address above to reply
Nov 13 '05 #16
>ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. 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 <63**************************@posting.google.com >
Peter Nilsson <ai***@acay.com.au> 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 (40°39.22'N, 111°50.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.
Nov 13 '05 #17
ai***@acay.com.au (Peter Nilsson) writes:
Thad Smith <th*******@acm.org> 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 <fj*@cs.mu.oz.au> | "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.
Nov 13 '05 #18
In <3F***************@acm.org> Thad Smith <th*******@acm.org> 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: Da*****@ifh.de
Nov 13 '05 #19
In <DJCpb.99053$Fm2.81929@attbi_s04> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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: Da*****@ifh.de
Nov 13 '05 #20
Brian Inglis wrote:

On Mon, 03 Nov 2003 10:17:18 -0700 in comp.std.c, Thad Smith
<th*******@acm.org> 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.


That means that the only signed integral types you can be certain won't
be promoted to 'int' are 'long' and 'long long', and similarly for
unsigned types. That causes a lot of portability problems when trying to
pass the size-named types to a variadic function. It also causes similar
problems when trying to pass them to functions declared without a
prototype, but that's easy to fix: just provide a prototype.
Nov 13 '05 #21
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. com>...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
[Cross posted to comp.std.c.] .... 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.


You'll have to explain that to me. Note: the above C code contains the
full definition of the <stdarg.h> for that platform; no C compiler
magic is needed, no special handling of code that contains va_arg().
It simply expands to C code which is interpreted in exactly the same
fashion that it would be if it were written by the user. The only
thing unportable about it is the assumptions it embodies about the
argument passing conventions.

Are you saying that static type analysis will somehow make the above
definitions work properly when given the original type of the
argument, rather than the promoted type? I don't see how that could
be: va_arg(ap,short) would seem to be incrementing ap by the wrong
amount, and using an lvalue with the wrong type to retrieve the value
it points at. I don't see how static type analysis can handle that.

Or are you saying that the above definitions can be re-written without
using implementation-specific extensions (of the syntax kind, not the
"static type analysis" kind) or compiler magic to produce the right
result? If so, could you give use the re-write?
Nov 13 '05 #22
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
Thad Smith <th*******@acm.org> wrote in message news:<3F***************@acm.org>... ....
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


Almost:

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

Nov 13 '05 #23
Oops! I missed one item; I should have included it in my previous
message:

ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. com>...

....
#define va_start(arg) )(&arg+sizeof(arg))


#define va_start(ap,arg) ((ap) = (char *) &arg) /* ? */


Sorry, that got messed up somehow, but your replacement is not the
correct fix. It should have been:

#define va_start(arg) ((char*)(&arg+sizeof(arg))
Nov 13 '05 #24
On 4 Nov 2003 11:10:30 -0800, ku****@wizard.net (James Kuyper) wrote:
Oops! I missed one item; I should have included it in my previous
message:

ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. com>...

...
> #define va_start(arg) )(&arg+sizeof(arg))


#define va_start(ap,arg) ((ap) = (char *) &arg) /* ? */


Sorry, that got messed up somehow, but your replacement is not the
correct fix. It should have been:

#define va_start(arg) ((char*)(&arg+sizeof(arg))


?

Do you mean ((char*)(&arg+1))?

Or perhaps (((char*)&arg)+sizeof(arg))?

Regards,

-=Dave
--
Change is inevitable, progress is not.
Nov 13 '05 #25

"Dan Pop" <Da*****@cern.ch> wrote in message
news:bo**********@sunnews.cern.ch...
In <DJCpb.99053$Fm2.81929@attbi_s04> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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 theyears. Most likely, this statement has never been executed, so it reallydoesn't matter what it compiles into. The problem comes when a program issupposed 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?
A good argument for the compile once, run anywhere system that Java uses.

Though some programs supply a set of test inputs and expected outputs
carefully selected to test as much of the program as possible. The only one
I can think of right now is TeX, though there are likely others.
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.
And some systems will let you link and run a program, even with compiler
errors.
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 theinclude file ndbm.h. It seems that it is now db.h, at least on the systemthat 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.


Well, yes. Though different amounts of experience will be necessary for
different problems.

-- glen
Nov 13 '05 #26
Dan Pop wrote:
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.


If size_t is being used properly, the question should never arise.

Nov 13 '05 #27
On Tue, 04 Nov 2003 17:09:51 -0500,
Douglas A. Gwyn <DA****@null.net> wrote
in Msg. <6e********************@comcast.com>
Dan Pop wrote:
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.


If size_t is being used properly, the question should never arise.


What do you mean by "used properly", and how does this proper usage avoid
the question of overflow?

--Daniel

--
"With me is nothing wrong! And with you?" (from r.a.m.p)
Nov 13 '05 #28
On 4 Nov 2003 15:33:56 GMT,
Dan Pop <Da*****@cern.ch> wrote
in Msg. <bo**********@sunnews.cern.ch>
A non-C programmer has no business using a C compiler or building and
installing C programs.


This is getting off-topic.

A normal computer user has plenty of business installing any kind of
programs though. There might be a C compiler under the hood of --say-- the
popular GNU "./configure && make && su root make install" mechanism, or
there might be some "Windows InstallShield" program at work. Both
approaches work fine most of the time, and, in my experience, both have
plenty of potential of installing broken an incomplete software, or of not
working at all. What difference does it make to a non-C-programmer? In
both cases, some obscure piece of software just fucks up.

(in the case of the C source code distribution, however, the C programmer
has a chance to have a go at the underlying problem which usually leads to
unjustifiable amounts of time spent on fixing it.)

--Daniel

--
"With me is nothing wrong! And with you?" (from r.a.m.p)
Nov 13 '05 #29
"James Kuyper" <ku****@wizard.net> wrote in message
news:8b**************************@posting.google.c om...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
Thad Smith <th*******@acm.org> wrote in message news:<3F***************@acm.org>... ... 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


Almost:

#if INT32_MAX <= INT_MAX && INT32_MIN >= INT_MIN


I thought about that, but same signed types cannot overlap ranges. So even
taking your argument that INT_MAX need not be one less than a power of two
into acount, a programmer should only need to check one bound.

Unless I'm missing something?

--
Peter
Nov 13 '05 #30
Da*****@cern.ch (Dan Pop) wrote in message news:<bo***********@sunnews.cern.ch>...
In <aE0pb.81932$HS4.680953@attbi_s01> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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


so to get the effect of a short, you would do something like this?

(short) va_arg(ap, int);

- nethlek
Nov 13 '05 #31
In <6e********************@comcast.com> "Douglas A. Gwyn" <DA****@null.net> writes:
Dan Pop wrote:
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.


If size_t is being used properly, the question should never arise.


Where does the standard define the proper usage of size_t?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #32
"James Kuyper" <ku****@wizard.net> wrote in message
news:8b**************************@posting.google.c om...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
ku****@wizard.net (James Kuyper) wrote in message news:<8b**************************@posting.google. com>...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>... > [Cross posted to comp.std.c.] ... > 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_arg(ap,type) ((type*)(ap+=sizeof(type)))[-1]

Try to figure out how to modify that without using any extensions to C
such as sizeof(promoted_typeof(type)).
I admit, that would be difficult.
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.


You'll have to explain that to me.


My point is that the (or an) extension seems to be easy, and from there,
va_arg is also easy.
Note: the above C code contains the
full definition of the <stdarg.h> for that platform; no C compiler
magic is needed, no special handling of code that contains va_arg().
It simply expands to C code which is interpreted in exactly the same
fashion that it would be if it were written by the user. The only
thing unportable about it is the assumptions it embodies about the
argument passing conventions.


The standard(s) did add mandatory extension requirements for things like
setjmp. [Even floating point type support was a non-trivial mandatory
'extension' for implementations on chipsets without FPUs in 1989.] I just
don't see how an extension to accomodate an alternative va_arg() which
accepts promotable types would be a significantly greater burdon.

I guess it's a question of degrees. [I still haven't heard if the concept
was even raised for C89 or C99.]

--
Peter
Nov 13 '05 #33

"Dave Hansen" <id**@hotmail.com> wrote in message
news:3f***************@News.CIS.DFN.DE...
On 4 Nov 2003 11:10:30 -0800, ku****@wizard.net (James Kuyper) wrote:
Oops! I missed one item; I should have included it in my previous
message:

ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>...
ku****@wizard.net (James Kuyper) wrote in message
news:<8b**************************@posting.google. com>......
> #define va_start(arg) )(&arg+sizeof(arg))

#define va_start(ap,arg) ((ap) = (char *) &arg) /* ? */


Sorry, that got messed up somehow, but your replacement is not the
correct fix.
Brain fade on my part.
It should have been:

#define va_start(arg) ((char*)(&arg+sizeof(arg))


?

Do you mean ((char*)(&arg+1))?

Or perhaps (((char*)&arg)+sizeof(arg))?


That looks like it, only with the extra ap...

#define va_start(ap,arg) ((ap) = ((char *) &arg + sizeof(arg)))

--
Peter
Nov 13 '05 #34
"Christian Bau" <ch***********@cbau.freeserve.co.uk> wrote in message
news:ch*********************************@slb-newsm1.svr.pol.co.uk...
In article <63**************************@posting.google.com >,
ai***@acay.com.au (Peter Nilsson) wrote:
[Cross posted to comp.std.c.]

"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> 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.


I see that in C99. Is it also in the previous standard? [It doesn't appear
to be in my copy of the C89 draft.]

In any case, plain char's signedness still causes a problem.

--
Peter
Nov 13 '05 #35
"Peter Nilsson" <ai***@acay.com.au> wrote in message
news:3f******@news.rivernet.com.au...
"Christian Bau" <ch***********@cbau.freeserve.co.uk> wrote in message
news:ch*********************************@slb-newsm1.svr.pol.co.uk...
In article <63**************************@posting.google.com >,
ai***@acay.com.au (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.]


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.


I see that in C99. Is it also in the previous standard? [It doesn't appear
to be in my copy of the C89 draft.]

In any case, plain char's signedness still causes a problem.


Include float in the list too.

--
Peter
Nov 13 '05 #36
In <YnVpb.80618$ao4.228900@attbi_s51> "Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> writes:
Well, yes. Though different amounts of experience will be necessary for
different problems.


However, even the not-so-experienced C programmer will have a starting
point for investigating the issue, while the non-C programmer will be
completely lost. We've seen that many times in c.l.c, when non-C
programmers experienced a *trivial* program build problem and asked here
for help.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #37
In <sl******************@kir.physnet.uni-hamburg.de> Daniel Haude <ha***@physnet.uni-hamburg.de> writes:
On 4 Nov 2003 15:33:56 GMT,
Dan Pop <Da*****@cern.ch> wrote
in Msg. <bo**********@sunnews.cern.ch>
A non-C programmer has no business using a C compiler or building and
installing C programs.
This is getting off-topic.

A normal computer user has plenty of business installing any kind of
programs though.


Only binary distributions, validated for his platform.
There might be a C compiler under the hood of --say-- the
popular GNU "./configure && make && su root make install" mechanism, or
there might be some "Windows InstallShield" program at work.


Both require administrator privileges, which the normal computer user is
not supposed to have. In practice, there are plenty of normal users that
do have administrator provileges, and this explains why many machines get
screwed up and reinstalled from scratch far more often than others.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #38
Peter Nilsson wrote:

"James Kuyper" <ku****@wizard.net> wrote in message
news:8b**************************@posting.google.c om...
ai***@acay.com.au (Peter Nilsson) wrote in message

news:<63**************************@posting.google. com>...
Thad Smith <th*******@acm.org> wrote in message news:<3F***************@acm.org>...
...
> 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


Almost:

#if INT32_MAX <= INT_MAX && INT32_MIN >= INT_MIN


I thought about that, but same signed types cannot overlap ranges.


Every arithmetic type has a range that overlaps the range of any other
arithmetic type, at the very least in the range from 0 to 127,
inclusive. Therefore, I presume that what you meant is not quite what
you said.

I presume that you're actually trying to refer to 6.2.5p8: " For any two
integer types with the same signedness and different integer conversion
rank (see 6.3.1.1), the range of values of the type with smaller integer
conversion rank is a subrange of the values of the other type."

Even so, it's still possible to have two types with the same upper limit
and different lower limits, or vice versa; that still makes the smaller
range a sub-range of the first one. In particular, it's not implausible
that an implementation might provide both 2's complement and 1's
complement types of the same size (one of which might need to be
emulated).
Nov 13 '05 #39
id**@hotmail.com (Dave Hansen) wrote in message news:<3f***************@News.CIS.DFN.DE>...
On 4 Nov 2003 11:10:30 -0800, ku****@wizard.net (James Kuyper) wrote:

....
#define va_start(arg) ((char*)(&arg+sizeof(arg))


?

Do you mean ((char*)(&arg+1))?

Or perhaps (((char*)&arg)+sizeof(arg))?


Either one will work, of course, with brevity favoring the first. I
should have been paying closer attention. Sorry!

I've spent nearly two weeks wrestling with a bug that causes a SIGSEGV
inside of malloc(), and which disappears when I link to a debugging
version of the malloc() family. I finally got somewhere when I wrote
my own debugging version of the malloc() family, but I'm feeling more
than a little frazzled lately. :-(
Nov 13 '05 #40
ne*****@tokyo.com (Mantorok Redgormor) wrote in message news:<41**************************@posting.google. com>...
....
so to get the effect of a short, you would do something like this?

(short) va_arg(ap, int);


Exactly.
Nov 13 '05 #41
In <41**************************@posting.google.com > ne*****@tokyo.com (Mantorok Redgormor) writes:
so to get the effect of a short, you would do something like this?

(short) va_arg(ap, int);


The cast is *useless*, due to the integral promotions. If the original
argument had type short, va_arg(ap, int) will yield a value that is
guaranteed to be in the range of the short type.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #42

"Dan Pop" <Da*****@cern.ch> wrote in message
news:bo**********@sunnews.cern.ch...
In <sl******************@kir.physnet.uni-hamburg.de> Daniel Haude <ha***@physnet.uni-hamburg.de> writes:
(snip)
A normal computer user has plenty of business installing any kind of
programs though. Only binary distributions, validated for his platform. There might be a C compiler under the hood of --say-- the
popular GNU "./configure && make && su root make install" mechanism, or
there might be some "Windows InstallShield" program at work.

Both require administrator privileges, which the normal computer user is
not supposed to have. In practice, there are plenty of normal users that
do have administrator provileges, and this explains why many machines get
screwed up and reinstalled from scratch far more often than others.


If you want to install it as root, such is in /usr/bin, /usr/local/bin, or
if it requires setuid root, yes.

Many programs can be installed in a users own directory and run fine from
there. The program that started this thread runs fine in a user directory.
A large fraction of the GNU programs will, also.

The trend toward fewer different OS's used by ordinary users is somewhat
solving that problem. I am not sure that is the best solution, though.

-- glen
Nov 13 '05 #43

"Dan Pop" <Da*****@cern.ch> wrote in message
news:bo***********@sunnews.cern.ch...
In <41**************************@posting.google.com > ne*****@tokyo.com (Mantorok Redgormor) writes:
so to get the effect of a short, you would do something like this?

(short) va_arg(ap, int);


The cast is *useless*, due to the integral promotions. If the original
argument had type short, va_arg(ap, int) will yield a value that is
guaranteed to be in the range of the short type.


But if you don't know that the original was of type short, and requiring int
in the va_arg call means you don't, then you can cast it. I am not sure
now if the compiler is required to enforce the cast. (If it is required to
enforce short, is it also required to enforce float?)

As an unrelated topic, did you ever find a web page where the menu didn't
include the value you wanted, download the html page, modify it, and load it
into the browser? CGI programs should not rely on the menu to enforce
limits. va_arg() won't enforce them, either.

-- glen
Nov 13 '05 #44
In article <3f******@news.rivernet.com.au>,
"Peter Nilsson" <ai***@acay.com.au> wrote:
"Peter Nilsson" <ai***@acay.com.au> wrote in message
news:3f******@news.rivernet.com.au...
"Christian Bau" <ch***********@cbau.freeserve.co.uk> wrote in message
news:ch*********************************@slb-newsm1.svr.pol.co.uk...
In article <63**************************@posting.google.com >,
ai***@acay.com.au (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.]

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.


I see that in C99. Is it also in the previous standard? [It doesn't appear
to be in my copy of the C89 draft.]

In any case, plain char's signedness still causes a problem.


Include float in the list too.


float doesn't cause problems; it will be converted to double and you
read it as double.

plain char _does_ cause a problem: A plain char value could be less than
0, it could also be greater than INT_MAX (not on the same implementation
though), so you don't know if it will be converted to int or unsigned
int. If you read it as int and I pass a value > INT_MAX => undefined
behavior. If you read it as unsigned int and I pass a value < 0 =>
undefined behavior.
Nov 13 '05 #45
James Kuyper <ku****@saicmodis.com> wrote in message news:<3F**************@saicmodis.com>...
Peter Nilsson wrote:

"James Kuyper" <ku****@wizard.net> wrote in message
news:8b**************************@posting.google.c om...
ai***@acay.com.au (Peter Nilsson) wrote in message news:<63**************************@posting.google. com>... > Thad Smith <th*******@acm.org> wrote in message news:<3F***************@acm.org>...
... > > 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

Almost:

#if INT32_MAX <= INT_MAX && INT32_MIN >= INT_MIN


I thought about that, but same signed types cannot overlap ranges.


Every arithmetic type has a range that overlaps the range of any other
arithmetic type, at the very least in the range from 0 to 127,
inclusive. Therefore, I presume that what you meant is not quite what
you said.

I presume that you're actually trying to refer to 6.2.5p8


Yes. I was (rather pathetically) trying to explain that ranges can't
overlap in the sense of... ( [ ) ].

--
Peter
Nov 13 '05 #46
Dan Pop wrote:
In <6e********************@comcast.com> "Douglas A. Gwyn" <DA****@null.net> writes:
If size_t is being used properly, the question should never arise.

Where does the standard define the proper usage of size_t?


The standard is not a tutorial.

Nov 13 '05 #47

"Douglas A. Gwyn" <DA****@null.net> wrote in message
news:6N********************@comcast.com...
Dan Pop wrote:
In <6e********************@comcast.com> "Douglas A. Gwyn" <DA****@null.net> writes:
If size_t is being used properly, the question should never arise.

Where does the standard define the proper usage of size_t?


The standard is not a tutorial.


Well, yes, but if size_t is supposed to hold a value that can be the
sizeof() something, the question is when would you want to multiply those.
The argument to malloc(), for example, should be the number of elements
desired * sizeof(one element).

Say, for example, I wanted to store the individual bytes of an int variable,
each in an int.

int num;
char *tmp;
int *bytes;
tmp=malloc(sizeof(num));
memcpy(tmp,(unsigned char*)&num,sizeof(num));
bytes=malloc(sizeof(num)*sizeof(*bytes));

Two size_t values multiplied together.

-- glen
Nov 13 '05 #48
In article <RQlqb.88888$9E1.452937@attbi_s52>,
"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> wrote:
"Douglas A. Gwyn" <DA****@null.net> wrote in message
news:6N********************@comcast.com...
Dan Pop wrote:
In <6e********************@comcast.com> "Douglas A. Gwyn" <DA****@null.net> writes:>If size_t is being used properly, the question should never arise.
Where does the standard define the proper usage of size_t?


The standard is not a tutorial.


Well, yes, but if size_t is supposed to hold a value that can be the
sizeof() something, the question is when would you want to multiply those.
The argument to malloc(), for example, should be the number of elements
desired * sizeof(one element).

Say, for example, I wanted to store the individual bytes of an int variable,
each in an int.

int num;
char *tmp;
int *bytes;
tmp=malloc(sizeof(num));
memcpy(tmp,(unsigned char*)&num,sizeof(num));
bytes=malloc(sizeof(num)*sizeof(*bytes));

Two size_t values multiplied together.


Two size_t values multiplied, and the result cast to size_t.

If the product fits into size_t, then everything is fine. If the product
does not fit into size_t, then you will not get the memory that you
wanted, no matter whether the multiplication produced defined or
implementation defined or undefined behavior.
Nov 13 '05 #49
In <ch*********************************@slb-newsm1.svr.pol.co.uk> Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <RQlqb.88888$9E1.452937@attbi_s52>,
"Glen Herrmannsfeldt" <ga*@ugcs.caltech.edu> wrote:
"Douglas A. Gwyn" <DA****@null.net> wrote in message
news:6N********************@comcast.com...
> Dan Pop wrote:
> > In <6e********************@comcast.com> "Douglas A. Gwyn"

<DA****@null.net> writes:
> >>If size_t is being used properly, the question should never arise.
> > Where does the standard define the proper usage of size_t?
>
> The standard is not a tutorial.


Well, yes, but if size_t is supposed to hold a value that can be the
sizeof() something, the question is when would you want to multiply those.
The argument to malloc(), for example, should be the number of elements
desired * sizeof(one element).

Say, for example, I wanted to store the individual bytes of an int variable,
each in an int.

int num;
char *tmp;
int *bytes;
tmp=malloc(sizeof(num));
memcpy(tmp,(unsigned char*)&num,sizeof(num));
bytes=malloc(sizeof(num)*sizeof(*bytes));

Two size_t values multiplied together.


Two size_t values multiplied, and the result cast to size_t.

If the product fits into size_t, then everything is fine. If the product
does not fit into size_t, then you will not get the memory that you
wanted, no matter whether the multiplication produced defined or
implementation defined or undefined behavior.


Yes, but if the result has type size_t, it is possible (and trivial)
to detect the overflow and handle the problem as appropriate, if the
result has type int, you have *already* invoked undefined behaviour:
too late for doing anything.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: Niels Dekker (no reply address) | last post by:
Is it possible for a standard compliant C++ compiler to have ( sizeof(short) < sizeof(int) ) and ( sizeof(short) == sizeof((short)0 + (short)0) ) ? Regards, Niels Dekker...
34
by: Andy | last post by:
Hi, Are 1 through 4 defined behaviors in C? unsigned short i; unsigned long li; /* 32-bit wide */ 1. i = 65535 + 3; 2. i = 1 - 3; 3. li = (unsigned long)0xFFFFFFFF + 3; 4. li = 1...
8
by: NilsNilsson | last post by:
I wrote this: short s1 = 0; short s2 = 1; short s3 = s1 + s2; And gor this compile error message: Cannot implicitly convert type 'int' to 'short' What is wrong here?
8
by: Ken Dopierala Jr. | last post by:
Hi, I'm reading the header file of a PCX image and I need to convert 2 bytes to a short. How would I go about doing this? I know that they are bytes 8 & 9 in my byte array. I'm not sure how to...
15
by: Steffen Loringer | last post by:
Hi, I'm using the following function to join 2 char (byte) into one short on a 32 bit X86 platform: unsigned short joinUnsigShort(unsigned char a,unsigned char b) { unsigned short val = 0;...
4
by: slougheed | last post by:
I encountered a problem after we had converted our declarations of 'unsigned short int' to uint16_t. In one instance, whoever did the conversion failed to delete the 'short' keyword so we had a...
10
by: Jim Langston | last post by:
Is the following well defined? size_t IntVal = 65537; unsigned short Length; if ( IntVal static_cast<unsigned short>( -1 ) ) { std::cout << "Value too long to fit in a short" << std::endl;...
10
by: nyhetsgrupper | last post by:
The following code result in the following compilation error: Error 1 Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?) short a = 1; short...
3
by: mathieu | last post by:
Could someone please tell me what is wrong with the following -ugly- piece of c++ code. Why when I explicititely set the template parameter my gcc compiler start getting confused: bla.cxx: In...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.