ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes:
In article <d3**********@nnrp.waia.asn.au>,
Richard Cavell <ri***********@mail.com> wrote:Using GCC on my G4, if I have a calculation like this:
#include <stdint.h>
uint64_t a = 0xffff * 0xffff ;
Integral values explicitly specified default to 'int' unless there
is a type modifier or the context provides reason to use a wider
type.
The type of an expression is not affected by the context in which it
appears. (A null pointer constant in a pointer context is the only
exception I can think of.) If it were, 0xffff and the result of the
multiplication would inherit the uint64_t type provided by the
context.
Very often the result of an expression is implicitly converted to some
type imposed by its context. For example (assuming 32-bit int),
given:
uint64_t a = 0xffff;
the constant 0xffff is of type int, but the result is implicitly
converted to uint64_t before being used to initialize a. But these
context-driven implicit conversions happen only on a single level;
the uint64_t context in
uint64_t a = 0xffff * 0xffff;
affects only the result of the multiplication, not the operands.
This makes using the fixed-width types in <stdint.h> tricky. You can
declare everything to be of some fixed size, and never refer to the
predefined types short, int, long, et al, but the ranges of the
predefined types can still affect the semantics of your code. The
language provides suffixes for signed and unsigned long and long long,
but not for the fixed-width types. Casts are probably the best
approach (one of the rare cases where casts are useful in portable
code).
--
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.