Using constants and their associated modifiers usi

2020-04-21 08:27发布

问题:

I was not sure what to call these flags, but what I am referring to is:

#define TEST_DEF 50000U //<- the "U" here

Google searching when you are not familiar with the jargon used to describe your question is futile.

What I am trying to do is use these constant definitions and make sure the value is only of a certain length, namely 8 or 16 bits.

How can I do this and what is it referred to as?

回答1:

There are five integer literal suffixes in C: u, l, ul, ll, and ull. Unlike nearly everything else in C they are case insensitive; also, ul and ull can be written as lu and llu respectively (however, lul is not acceptable).

They control the type of the constant. They work approximately like this:

literal │ type
────────┼───────────────────────
500     │ int
500u    │ unsigned int
500l    │ long int
500ul   │ unsigned long int
500ll   │ long long int
500ull  │ unsigned long long int

This is only an approximation, because if the constant is too large for the indicated type, it is "promoted" to a larger type. The rules for this are sufficiently complicated that I'm not going to try to describe them. The rules for "promoting" hexadecimal and octal literals are slightly different than the rules for "promoting" decimal literals, and they are also slightly different in C99 versus C90 and different again in C++.

Because of the promotion effect, is not possible to use these suffixes to limit constants to any size. If you write 281474976710656 on a system where int and long are both 32 bits wide, the constant will be given type long long even though you didn't say to do that. Moreover, there are no suffixes to force a constant to have type short nor char. You can indicate your intent with the [U]INT{8,16,32,64,MAX}_C macros from <stdint.h>, but those do not impose any upper limit either, and on all systems I can conveniently get at right now (OSX, Linux), *INT8_C and *INT16_C actually produce values with type (unsigned) int.

Your compiler may, but is not required to, warn if you write ((uint8_t) 512) or similar (where 512 is a compile-time constant value outside the range of the type. In C11 you can use static_assert (from <assert.h>) to force the issue but it might be a bit tedious to write.



回答2:

For integers, the section of the standard (ISO/IEC 9899:2011 — aka C2011 or C11) defining these suffixes is:

§6.4.4.1 Integer constants

Where it defines the integer-suffixes:

integer-suffix:
    unsigned-suffix long-suffixopt
    unsigned-suffix long-long-suffix
    long-suffix unsigned-suffixopt
    long-long-suffix unsigned-suffixopt

unsigned-suffix: one of
    u U

long-suffix: one of
    l L

long-long-suffix: one of
    ll LL

The corresponding suffixes for floating point numbers are f, F, l and L (for float and long double).

Note that it would be perverse to use l because it is far too easily confused with 1, so the qualifiers are most often written with upper-case letters.

If you want to create integer literals that are of a given size, then the facilities to do so are standardized by <stdint.h> (added in C99).

The header (conditionally) defines fixed-size types such as int8_t and uint16_t. It also (unconditionally) provides minimum-sized types such as int_least8_t and uint_least16_t. If it cannot provide exact types (perhaps because the word size is 36 bits, so sizes 9, 18 and 36 are handled), it can still provide the least types.

It also provide macros such as INT8_C which ensure that the argument is an int_least8_t value.

Hence, you could use:

#include <stdint.h>

#define TEST_DEF UINT16_C(50000)

and you are guaranteed that the value will be at least 16 bits of unsigned integer, and formatted/qualified correctly.

§7.20.4 Macros for integer constants

¶1 The following function-like macros expand to integer constants suitable for initializing objects that have integer types corresponding to types defined in <stdint.h>. Each macro name corresponds to a similar type name in 7.20.1.2 or 7.20.1.5.

¶2 The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.

¶3 Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.

7.20.4.1 Macros for minimum-width integer constants

¶1 The macro INTN_C(value) shall expand to an integer constant expression corresponding to the type int_leastN_t. The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t. For example, if uint_least64_t is a name for the type unsigned long long int, then UINT64_C(0x123) might expand to the integer constant 0x123ULL.



回答3:

This is an unsigned literal (U is suffix). See: http://en.cppreference.com/w/cpp/language/integer_literal