qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] block: Explicitly specify 'unsigned long long'


From: Laszlo Ersek
Subject: Re: [Qemu-devel] [PATCH] block: Explicitly specify 'unsigned long long' for VHDX 64-bit constants
Date: Fri, 14 Mar 2014 18:27:07 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.3.0

 On 03/14/14 17:51, Richard W.M. Jones wrote:
> On Fri, Mar 14, 2014 at 05:26:06PM +0100, Laszlo Ersek wrote:
>> (b) UINT64_C() is for "uint_least64_t" (7.18.4.1 Macros for
>> minimum-width integer constants). "uint_least64_t" is a required type
>> (7.18.1.2 Minimum-width integer types).
>>
>> In practice I'd say it doesn't matter which one we use:
>> - ULL suffix is gnu89,
>> - UINT64_C() macro is gnu89,
>> - "unsigned long long" could be wider in general than 64 bits,
>> - "uint_least64_t" too could be wider in general than 64 bits,
>> - for us both results in uint64_t exactly.
>>
>> So the above is a tie, but the ULL suffix is just nicer. (IMHO :))
> 
> Interesting discussion here:
> 
> https://stackoverflow.com/questions/16360828/what-is-the-purpose-of-macros-for-minimum-width-integer-constants
> 
> suggesting that these macros aren't well-specified.  Ho hum.

I think they are well specified. UINT64_C(x) is the same as
((uint_least64_t)(x)), only the macro replacement text in the latter
uses the appropriate suffix rather than a cast. It produces one integer
constant. (Specific syntax in 6.4.4.1 Integer constants.)

(Note that when I say "the same", the domain of "x" is restricted to "a
decimal, octal, or hexadecimal constant [...] with a value that does not
exceed the limits for the corresponding type.)


*Why* someone would want to use an integer constant with type
"uint_least64_t" is a separate matter. One example follows -- assume all
of the below:
- suppose you write portable C99 source code,
- hence you can't take uint64_t for granted,
- you want a constant that's otherwise small enough to be represented as
"int",
- but you want that constant to trigger the "usual arithmetic
conversions" (see 6.3.1.8) to evaluate expressions that the constant
participates in in at least 64 bits,
- you want the narrowest type that allows you to do this.

Consider

  #define MY_CONSTANT UINT64_C(123)

  /* ... */
  {
    int i = ...;

    ... (MY_CONSTANT * i) ...
  }

If the mathematical result of the multiplication (ie. the math product)
fits in 64 value bits, then the result of the above C multiplication
will be able to *represent* it. If you just write

  #define MY_CONSTANT2 123


  /* ... */
  {
    int i = ...;

    ... (MY_CONSTANT * i) ...
  }

then this may not be the case.

You ensure this "safer" representation (without explicit casts in the
client expressions) by encoding the wider type in the constant itself.
You could use the explicit cast there:

  #define MY_CONSTANT ((uint_least64_t)123)

but UINT64_C() promises not to produce a cast, just an integer constant.
You might care about that for whatever reason.

(You could of course use

  #define MY_CONSTANT 123ULL

too, but that wouldn't select a minimal type for your purpose, portably
speaking (when you don't know much about your target platform).)

I think the mechanics of UINT64_C() are well specified, just the purpose
is obscure :) 7.18.4 "Macros for integer constants" itself states (about
all the macros together):

    The following function-like macros [...] expand to integer constants
    suitable for initializing objects that have integer types
    corresponding to types defined in <stdint.h>. [...]

This question could be asked in the comp.lang.c Usenet group (and then
obsessed over for a few days! :))

Thanks
Laszlo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]