va_arg and short

  • Thread starter Glen Herrmannsfeldt
  • Start date
D

Dan Pop

In said:
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
 
G

Glen Herrmannsfeldt

Dan Pop said:
Only binary distributions, validated for his platform.
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
 
G

Glen Herrmannsfeldt

Dan Pop said:
In <[email protected]> (e-mail address removed)
(Mantorok Redgormor) said:
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
 
C

Christian Bau

"Peter Nilsson said:
Peter Nilsson said:
Christian Bau said:
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.
 
P

Peter Nilsson

James Kuyper said:
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... ( [ ) ].
 
G

Glen Herrmannsfeldt

Douglas A. Gwyn said:
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
 
C

Christian Bau

"Glen Herrmannsfeldt said:
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.
 
D

Dan Pop

In said:
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
 
D

Dan Pop

In said:
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.

But, in this case, by installing and using it you're not compromising the
system's integrity or other people's data integrity, you're only
compromising the integrity of *your* data. If things do go wrong,
you get what you deserve.

If you want to shoot yourself in the foot, a good OS should not prevent
you from doing it ;-)

Dan
 
D

Dan Pop

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, ^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Where did you get this idea from? You require int because you *know* that
short is promoted to int. However, if the function specification required
short, there is no point in casting. See below.
then you can cast it.

What for? If the caller provided a value outside of the range of short,
the cast will prevent you from detecting the error condition (the runtime
equivalent of casting malloc's return value). If the caller provided
a good value, the cast buys you nothing (the analogy with casting malloc
still holds). And if you later decide to change the type of the argument
from short to int, the cast becomes a potential bug (if you forget to
remove it) and no compiler is going to warn you about it. It's a typical
example of a "gratuitous" cast having a fairly high price.
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?)

I don't understand what you're talking about. The compiler doesn't
enforce anything, it merely performs the default argument promotions when
calling the function and nothing else.
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.

va_arg() doesn't enforce anything. It merely retrieves parameter values.
And your point is?

Dan
 
G

Glen Herrmannsfeldt

Dan Pop said:
In <99aqb.82956$275.242639@attbi_s53> "Glen Herrmannsfeldt" ^^^^^^^^^^^^^^^^^

Where did you get this idea from? You require int because you *know* that
short is promoted to int. However, if the function specification required
short, there is no point in casting. See below.

If I read a value into a short variable with scanf() I can be 100% sure that
the value in the variable is within the range of a short. I might, for
example, use it as an array subscript knowing it couldn't be outside the
range of a short.
What for? If the caller provided a value outside of the range of short,
the cast will prevent you from detecting the error condition (the runtime
equivalent of casting malloc's return value). If the caller provided
a good value, the cast buys you nothing (the analogy with casting malloc
still holds). And if you later decide to change the type of the argument
from short to int, the cast becomes a potential bug (if you forget to
remove it) and no compiler is going to warn you about it. It's a typical
example of a "gratuitous" cast having a fairly high price.

If I expect a short argument, assume that its value is within the range of a
short, but a sneaky caller supplies an int instead, I might, for example,
access outside of an array. The cast, if enforced, ensures that the value
is within the range of a short.

Though the & operator is probably better at limiting the range of values
than a (short) cast.

Is the compiler required to enforce the cast, such that the value can never
be outside the range of a short?

Is it required to enforce (float), even on machines with extended floating
point form where all arithmetic is done with a 64 bit mantissa?
I don't understand what you're talking about. The compiler doesn't
enforce anything, it merely performs the default argument promotions when
calling the function and nothing else.

If the compiler enforces the cast it will truncate (or something else) the
value to fit within the range of a short, even though it is supplied, and is
assigned to, an in variable.
va_arg() doesn't enforce anything. It merely retrieves parameter values.
And your point is?

The claim, not by me, was that the (short) cast on va_arg() would give the
effect of a short. You were claiming that the cast was useless. I
believe, but I am not sure, that with the cast the compiler is required to
convert to a short before assigning, or otherwise using, the return value of
(short)va_arg().

-- glen
 
D

Douglas A. Gwyn

Glen said:
bytes=malloc(sizeof(num)*sizeof(*bytes));

The example looks broken, but anyway,
Two size_t values multiplied together.

the issue was wanting to get wraparound modulo wordsize,
not what you would want here (or in any other legitmate
use of size_t).
 
D

Dan Pop

In said:
The example looks broken, but anyway,


the issue was wanting to get wraparound modulo wordsize,
not what you would want here (or in any other legitmate
use of size_t).

That's precisely what he wanted here: when multiplying two size_t values
together, to compute the size of a large object, overflow may happen and
you may want to be able to detect it.

As usual, you're replying to a post you haven't bothered to read
carefully.

Dan
 
D

Dan Pop

If I read a value into a short variable with scanf() I can be 100% sure that
the value in the variable is within the range of a short. I might, for
example, use it as an array subscript knowing it couldn't be outside the
range of a short.

How does this fit into the context of the discussion?
If I expect a short argument, assume that its value is within the range of a
short, but a sneaky caller supplies an int instead, I might, for example,
access outside of an array. The cast, if enforced, ensures that the value
is within the range of a short.

And without the cast you have the chance to detect the error, instead of
silently accessing a "random" array element. Furthermore, how many times
have you declared arrays having SHRT_MAX elements?

As I have already *clearly* explained, the cast destructively hides the
caller error.
Is the compiler required to enforce the cast, such that the value can never
be outside the range of a short?

What the hell are you talking about? If you specify int in the va_arg
macro invocation, how can the compiler be required to enforce any cast to
short?
Is it required to enforce (float), even on machines with extended floating
point form where all arithmetic is done with a 64 bit mantissa?

What the hell are you talking about?
If the compiler enforces the cast it will truncate (or something else) the
value to fit within the range of a short, even though it is supplied, and is
assigned to, an in variable.

Why the hell should you expect the compiler to enforce any cast to
shorter types, when you specify int or double? I have clearly explained
to you that you cannot specify short of float in a va_arg invocation,
haven't I?
The claim, not by me, was that the (short) cast on va_arg() would give the
effect of a short. You were claiming that the cast was useless.

And I have *clearly* explained why, but you chose to ignore my
explanations and arguments.
I
believe, but I am not sure, that with the cast the compiler is required to
convert to a short before assigning, or otherwise using, the return value of
(short)va_arg().

This is, of course, true, but POINTLESS, as I have already explained in
my previous post:

1. If the caller supplied a short value, the cast achieves nothing.

2. If the caller supplied a value out of the range of short, the cast
prevents you from detecting the error. You *will* end up with a short
value, but it will be the *wrong* short value and you'll never know it.
Furthermore, C99 allows such a cast to crash your program, but I don't
believe that any implementor would do that.

Dan

Dan
 
M

Mark Gordon

If I read a value into a short variable with scanf() I can be 100%
sure that the value in the variable is within the range of a short.
I might, for example, use it as an array subscript knowing it couldn't
be outside the range of a short.

I think that Dan's point is that 6 weeks later someone else calls that
function (or does some other change) without realising that you expect
a short.
If I expect a short argument, assume that its value is within the
range of a short, but a sneaky caller supplies an int instead, I
might, for example, access outside of an array. The cast, if
enforced, ensures that the value is within the range of a short.

It doesn't. The following are the same as far as ISO C is concerned.

short i = va_arg(ap,int);
short i = (short)va_arg(ap,int);

According to P197 of K&R2, "When any integer is converted to a signed
tpe, the value is unchanged if it can be represented in the new type and
is implementation defined otherwise".

So casting or assigned an integer to a short is not guaranteed to
enforce the range, and if the implementation documented that on
accessing the short you might get the original int value (say because it
is stored in a register and has not been truncated) then I would assume
it would still be conforming and your use of it as an array index could
then invoke undefined behaviour.
Though the & operator is probably better at limiting the range of
values than a (short) cast.

I assume you mean passing a pointer to a short. However, that has the
potentially undesirable side effect of preventing passing a constant for
that parameter.
Is the compiler required to enforce the cast, such that the value can
never be outside the range of a short?

No. See above.

If, on the other hand, you use unsigned short the result is defined by
the standard, but it is unlikely to be what you want.

IMHO you should write code to check the value yourself if you really
want a short when it is being passed as part of a varidac parameter.
Either that or accept that out of range values will invoke incorrect
behaviour (depending on your use you may not invoke UB).
Is it required to enforce (float), even on machines with extended
floating point form where all arithmetic is done with a 64 bit
mantissa?

In that case you may well find that short and double are identical.
If the compiler enforces the cast it will truncate (or something else)
the value to fit within the range of a short, even though it is
supplied, and is assigned to, an in variable.

It does not have to.

IIRC when casting from double to float it has to do the cast to enforce
the correct precision, but it still does not have to do what you expect
for out of range values.
The claim, not by me, was that the (short) cast on va_arg() would give
the effect of a short. You were claiming that the cast was useless.
I believe, but I am not sure, that with the cast the compiler is
required to convert to a short before assigning, or otherwise using,
the return value of(short)va_arg().

If you are assigning to a short it makes not difference.
If the value is converted to a short (either by cast or due to
assignment) and it is out of range you invoke implementation defined
behaviour which I would expect to not be what you want.
 
J

James Kuyper

Glen Herrmannsfeldt said:
If I read a value into a short variable with scanf() I can be 100% sure that
the value in the variable is within the range of a short. I might, for
example, use it as an array subscript knowing it couldn't be outside the
range of a short.

Where did scanf() enter into this?
If I expect a short argument, assume that its value is within the range of a
short, but a sneaky caller supplies an int instead, I might, for example,
access outside of an array. The cast, if enforced, ensures that the value
is within the range of a short.

I don't know what "enforced" means to you; it means nothing to the
standard. If the value returned by va_arg(ap,int) is outside the valid
range of 'short', the behavior is undefined.
Though the & operator is probably better at limiting the range of values
than a (short) cast.

I have no idea what you mean by that statement.
Is the compiler required to enforce the cast, such that the value can never
be outside the range of a short?

The behavior is undefined; nothing is required.
If the compiler enforces the cast it will truncate (or something else) the
value to fit within the range of a short, even though it is supplied, and is
assigned to, an in variable.

In that case, the answer is "No"; there's no such requirement in the
standard. With unsigned types you have a guarantee of wrap-around, so
that

UINT_MAX+1U == 0U

but there's no such guarantee with any other type.
The claim, not by me, was that the (short) cast on va_arg() would give the
effect of a short. ...

It will, when the argument is in range, produce the same exact value
with a type of short. What it does when the value is out of range is
undefined.
... You were claiming that the cast was useless. I
believe, but I am not sure, that with the cast the compiler is required to
convert to a short before assigning, or otherwise using, the return value of
(short)va_arg().

Yes, it is, when the value is in range.
 
D

Dan Pop

In said:
I don't know what "enforced" means to you; it means nothing to the
standard. If the value returned by va_arg(ap,int) is outside the valid
range of 'short', the behavior is undefined.

Chapter and verse, please.

Dan
 
D

Douglas A. Gwyn

Dan said:
That's precisely what he wanted here: when multiplying two size_t values
together, to compute the size of a large object, overflow may happen and
you may want to be able to detect it.

What is actually wanted is to enforce the total size limit of
SIZE_MAX. That is not necessarily the same as checking for
wraparound.
As usual, you're replying to a post you haven't bothered to read
carefully.

As usual, you haven't bothered to understand any point of view
but your own.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,573
Members
45,046
Latest member
Gavizuho

Latest Threads

Top