Pregunta

I like to initialize my variables to some "dummy" value and have started to use int64_t and uint64_t. So far, it looks like there are at least three ways I could initialize an int64_t to a particular value (and with slight changes for the unsigned equivalent):

int64_t method_one   = 0;
int64_t method_two   = 0LL;
int64_t method_three = INT64_C(0);

I use GCC and target OS X and Linux. I'd like to pick a method that aims for ease of portability and clarity — but correctness, above all. Am I overthinking this, or is there a "best" or "most recommended" approach for initializing this variable type, for any particular value I throw at it (which is within its bounds, of course)?

¿Fue útil?

Solución

int64_t method_one   = 0;

...is perfectly reasonable. C99 (see e.g. draft here; yes, I know it's not the most recent standard any more, but it's the one that introduced the int<N>_t types) says that:

  • the 0 has type int (§6.4.4.1 para.5);
  • the type of the expression is int64_t (§6.5.16 para.3);
  • the type of the right-hand side will be converted to the type of the expression (§6.5.16.1 para.2);
  • this conversion will not change the value (§6.3.1.3 para.1).

So there's nothing wrong with that at all, and the lack of additional clutter makes it the most readable of the options when initialising to 0 or anything else in the range of an int.

int64_t method_two   = 0LL;

int64_t is not guaranteed to be the same as long long; however, this should in fact work portably for any signed 64-bit value as well (and similarly ULL for unsigned 64-bit values): long long (and unsigned long long) should be at least 64 bits in a C99-compliant implementation (§5.2.4.2.1), so LL (and ULL) should always be safe for initialising 64-bit values.

int64_t method_three = INT64_C(0);

This is arguably a better option for values which may be outside the range of an int, as it expresses the intent more clearly: INT64_C(n) will expand to something appropriate for any n in (at least) a 64-bit range (see §7.18 in general, and particularly §7.8.4.1).


In practice, I might well use any of the above, depending on context. For example:

uint64_t counter = 0;

(Why add unnecessary clutter?)

uint64_t some_bit = 1ULL << 40;

(1 << 40 simply won't work unless int is unusually wide; and UINT64_C(1) << 40 seems less readable to me here.)

uint64_t some_mask = UINT64_C(0xFF00FF00FF00FF00);

(In this case, explicitly calling out the value as a 64-bit constant seems more readable to me than writing 0xFF00FF00FF00FF00ULL.)

Otros consejos

Personnally, I would use the third, which is the most portable way to achieve this.

#include <stdint.h>

int64_t method_three  = INT64_C(0);
uint64_t method_three = UINT64_C(0);

Anyway, I don't think it's a very important thing.

According to the ANSI C standard, the suffix for a long long int and unsigned long long int is LL and ULL respectively:

octal or hexadecimal suffixed by ll or LL long long int, unsigned long long int decimal, octal, or hexadecimal suffixed by both u or U, and ll or LL unsigned long long int

If you know that int64_t is defined as:

typedef signed long long int int64_t

Then method two is most definitely the correct one:

int64_t method_two   = 0LL;
uint64_t method_two   = 0ULL;

Edit:

Keeping in mind the portability issues, and the fact that it's not guaranteed to be defined as long long, then it would be better to use the third method:

INT64_C()
UINT64_C()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top