Какой инициализатор подходит для int64_t?

Мне нравится инициализировать мои переменные до некоторого значения "dummy" и начали использовать int64_t и uint64_t. До сих пор, похоже, существует как минимум три способа инициализировать int64_t для определенного значения (и с небольшими изменениями для беззнакового эквивалента):

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

Я использую GCC и целевые ОС X и Linux. Я хотел бы выбрать метод, который направлен на упрощение переносимости и ясности, но, прежде всего, на правильность. Могу ли я это высказать, или существует ли "лучший" или "самый рекомендуемый" подход для инициализации этого типа переменной для любого конкретного значения, которое я бросаю на него (что, конечно, в пределах его границ)?

Ответы

Ответ 1

int64_t method_one   = 0;

... вполне разумно. C99 (см., Например, проект здесь; да, я знаю, что это не самый последний стандарт, но тот, который представил типы int<N>_t), говорит, что:

  • 0 имеет тип int (§6.4.4.1, пункт 5);
  • тип выражения int64_t (§6.5.16, пункт 3);
  • тип правой части будет преобразован в тип выражения (§6.5.16.1, параграф 2);
  • это преобразование не изменит значение (§6.3.1.3 п. 1).

Таким образом, нет ничего плохого в этом, и отсутствие дополнительного беспорядка делает его наиболее читаемым из параметров при инициализации до 0 или чего-либо еще в диапазоне int.

int64_t method_two   = 0LL;

int64_t не гарантируется как long long; однако, на самом деле это должно работать и для любого подписанного 64-битного значения (и аналогично ULL для неподписанных 64-битных значений): long longunsigned long long) должно быть не менее 64 бит в C99- (§5.2.4.2.1), поэтому LLULL) всегда должно быть безопасным для инициализации 64-битных значений.

int64_t method_three = INT64_C(0);

Это, возможно, лучший вариант для значений, которые могут быть вне диапазона int, поскольку он более четко выражает намерение: INT64_C(n) будет расширяться до чего-то подходящего для любого n в (по крайней мере) a 64-битный диапазон (см. §7.18 в целом и, в частности, §7.8.4.1).


На практике я мог бы использовать любой из вышеперечисленных, в зависимости от контекста. Например:

uint64_t counter = 0;

(Зачем добавлять лишний беспорядок?)

uint64_t some_bit = 1ULL << 40;

(1 << 40 просто не работает, если int необычно широк, а UINT64_C(1) << 40 представляется мне менее читаемым.)

uint64_t some_mask = UINT64_C(0xFF00FF00FF00FF00);

(В этом случае явное вызывание значения в виде 64-битной константы кажется мне более читаемым, чем запись 0xFF00FF00FF00FF00ULL.)

Ответ 2

В общем, я бы использовал третий, который является самым переносимым способом для достижения этого.

#include <stdint.h>

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

Во всяком случае, я не думаю, что это очень важно.

Ответ 3

В соответствии со стандартом ANSI C суффикс для long long int и unsigned long long int равен LL и ULL соответственно:

восьмеричный или шестнадцатеричный суффикс ll или LL long long int, без знака long long int decimal, восьмеричный или шестнадцатеричный, суффикс как u, так и U, и ll или LL unsigned long long int

Если вы знаете, что int64_t определяется как:

typedef signed long long int int64_t

Тогда метод два наиболее определенно правильный:

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

Изменить:

Помня о проблемах переносимости и о том, что он не может быть определен как long long, тогда было бы лучше использовать третий метод:

INT64_C()
UINT64_C()