The code is something like this,
void func(void)
{
unsigned long tmout_usec;
if (x==0) tmout_usec=15000000;
else tmout_usec = 30000000;
...
}
Then somebody points out to me that if I don't put a "L" after the
number, compiler would cast the number to an integer. So according to
him, it should be tmout_usec=15000000L and tmout_usec=30000000L,
otherwise, I'd lose my accuracy. And his argument is "The cast is done
because of the rules of C -- the two sides of the "=" are treated
separately. So, it takes the 15000000 and then it follows the rule
that says to cast it to an int unless something else is not an int.
That is why the "L" exists and is needed. The compiler would have
generated a warning for you.
"
However after I look at the assembly it generates, the original numbers
are preseved. And I don't see a compiler warning with the highest level
set.
Please comment. Thanks.
Lee
> Hello, I am curious to know whehter it is absolutely necessary to put a
> L behind a number if it is intended to be a Long type?
No, it is not absolutely necessary. But it is highly recommended. In
most cases it will not make any difference, But in some cases it may
cause hard-to-find program problems. And it can never cause a
problem, so why not?
> The code is something like this,
>
> void func(void)
> {
> unsigned long tmout_usec;
>
> if (x==0) tmout_usec=15000000;
The literal "15000000" either has type signed int, if a signed int on
your implementation can contain the value 15000000, or of type signed
long, which must be able to contain this value. But if you are using
a literal for a value for an unsigned long, you should use the suffix
"UL", not just L.
> else tmout_usec = 30000000;
Same thing here. But where you could run into problems, assuming
common 32-bit platforms, is:
tmout_usec = 3000000000;
...because this value is too large to fit into a 32-bit signed long,
even though it will fit into a 32-bit unsigned long. If you have an
implementation that supports the C99 long long type, the constant will
have the type "signed long long", and be converted to unsigned long
with the correct value. If your compiler supports an older C standard
and the literal is larger than the largest value that signed long can
contain, the result you get is implementation-defined, and maybe not
what the programmer intended.
> ...
> }
>
> Then somebody points out to me that if I don't put a "L" after the
> number, compiler would cast the number to an integer. So according to
Somebody does not know their terminology. The compiler never casts
anything unless there is a cast operator in the source code.
A decimal integer literal has the type of the first one of these into
which its value fits: signed int, signed long, signed long long. A
decimal integer literal will never result in any unsigned integer
type.
> him, it should be tmout_usec=15000000L and tmout_usec=30000000L,
One of you is wring. Since tmout_usec has type unsigned long, if you
use a suffix it should be UL.
> otherwise, I'd lose my accuracy. And his argument is "The cast is done
Yes, you could, if the literal has a value too great to fit into the
largest signed integer type your platform provides.
But there is no cast.
> because of the rules of C -- the two sides of the "=" are treated
> separately. So, it takes the 15000000 and then it follows the rule
> that says to cast it to an int unless something else is not an int.
> That is why the "L" exists and is needed. The compiler would have
> generated a warning for you."
There is no rule that causes any cast in this code. The type of a
literal is based solely on the rules for literals, and not on what you
do with it afterwards.
> However after I look at the assembly it generates, the original numbers
> are preseved. And I don't see a compiler warning with the highest level
> set.
>
> Please comment. Thanks.
My only comment is this:
Always suffixing literals with the type they will be used as can NEVER
cause an error in the program and can SOMETIMES prevent an error.
So what possible reason can you have for not doing this? The extra
typing is not worth the fact that once in a while it will prevent a
real error?
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
What if you don't know the type of the value? For example:
size_t size = 1000000000;
Whether than should be 1000000000U or 1000000000UL depends on how the
implementation defines size_t.
(This doesn't apply to the OP's example, which used unsigned long
explicitly.)
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
> Jack Klein <jack...@spamcop.net> writes:
> [...]
> > Always suffixing literals with the type they will be used as can NEVER
> > cause an error in the program and can SOMETIMES prevent an error.
> >
> > So what possible reason can you have for not doing this? The extra
> > typing is not worth the fact that once in a while it will prevent a
> > real error?
>
> What if you don't know the type of the value? For example:
>
> size_t size = 1000000000;
>
> Whether than should be 1000000000U or 1000000000UL depends on how the
> implementation defines size_t.
>
> (This doesn't apply to the OP's example, which used unsigned long
> explicitly.)
I dunno about that. I'd use 1000000000UL, or maybe even 1000000000ULL
in that case. Could even use 1000000000L, since this particular value
is less than the minimum allowed LONG_MAX. There's absolutely nothing
to lose, and really no problem with making the type of the literal
higher rank than the destination type.
There are only two possibilities:
1. The value will fit into a size_t.
2. The value will not, and therefore will be truncated under the
defined behavior of conversion to a lesser rank unsigned type.
If the value fits, the type of the constant makes no difference. The
only issue lies in the other direction, if the value of the literal
might be outside the range of int, to keep it from being truncated
before being used to initialize or assign to the destination type.
Of course, if I were using that value with a size_t and I was
concerned about the possibility of the code being ported to a platform
where size_t was 16 bits, I'd throw in an assert or some other run
time check.
I'll admit that I'm being lazy and not looking things up, but isn't
there a macro in one of the headers that turns strings like this
into constants of the appropriate type. <stdint.h>?
max
Yes, but only for the intn_t, uintn_t exact width types, and for
intmax_t and uintmax_t. There are no such required macros for types
like size_t and ptrdiff_t.
There are macros for SIZE_MAX and some others, but these, like the
choice of unsigned integer type to use for size_t in the first place,
are implementation-defined.
> On 7 Feb 2005 16:11:31 -0800, "L. Hao" <jwcl...@gmail.com> wrote in
> comp.std.c:
<snip>
> > else tmout_usec = 30000000;
>
> Same thing here. But where you could run into problems, assuming
> common 32-bit platforms, is:
>
> tmout_usec = 3000000000;
>
> ...because this value is too large to fit into a 32-bit signed long,
> even though it will fit into a 32-bit unsigned long. If you have an
> implementation that supports the C99 long long type, the constant will
> have the type "signed long long", and be converted to unsigned long
> with the correct value. If your compiler supports an older C standard
> and the literal is larger than the largest value that signed long can
> contain, the result you get is implementation-defined, and maybe not
> what the programmer intended.
>
No, in C90 the constant has type unsigned long, which must handle this
value, and the declaration of tmout_usec (snipped) was that same type.
If the variable were signed long, then you would have an I-D result of
the conversion (or possibly a signal), and with decent QoI a warning.
<snip>
> A decimal integer literal has the type of the first one of these into
> which its value fits: signed int, signed long, signed long long. A
> decimal integer literal will never result in any unsigned integer
> type.
>
In C90 it will go to unsigned long if it exceeds signed long. C99
fixed this anomaly, perhaps to allow for extended or future-standard
'even longer' types, perhaps just because it was yucky. <G>
<snip>
> Always suffixing literals with the type they will be used as can NEVER
> cause an error in the program and can SOMETIMES prevent an error.
>
It also allows one (me!) to do 3000UL * 1000UL * 1000UL -- and perhaps
#define USEC(x) ((x)*1000UL*1000UL) -- to avoid (mis)counting zeros.
- David.Thompson1 at worldnet.att.net