Как я могу подтвердить диапазон длинных целых чисел без знака в C? - PullRequest
0 голосов
/ 26 апреля 2018

unsigned long имеет 8 байтов на моем Linux gcc.

unsigned long long также имеет 8 байтов на моем Linux gcc.

Поэтому я думаю, что диапазон целых чисел, которые они могут показать, составляет от 0 мин до (2 ^ 64 - 1) макс .

Теперь я хочу подтвердить, если я 'm правильно.

Вот мой код :

#include <stdio.h>
int main(void)
{
    printf("long takes up %d bytes:\n", sizeof(long));
    printf("long long takes up %d bytes:\n", sizeof(long long));

    unsigned long a = 18446744073709551615;
    a++;
    printf("a + 1 = %lu\n", a); 

    unsigned long long b = 18446744073709551615;
    b++;
    printf("b + 1 = %llu\n", b); 

    return 0;
}

Однако код не может быть скомпилирован, и я получаю следующее предупреждение:

warning: integer constant is so large that it is unsigned

Где я сделал не так?Как я могу изменить код?

Ответы [ 5 ]

0 голосов
/ 26 апреля 2018

Как мне подтвердить диапазон длинных целых без знака в C?

Best , просто используйте макросы из <limits.h>.Он лучше сам документирует намерения кода.

unsigned long long b_max = ULLONG_MAX;

В качестве альтернативы присвойте -1 типу unsigned .Поскольку -1 не входит в диапазон типа unsigned , он будет преобразован в целевой тип путем добавления значения MAX этого типа плюс 1. Работает даже на редких машинах с отступом.

... если новый тип без знака, значение преобразуется путем многократного сложения или вычитания значения, превышающего максимальное значение, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне новоготип.C11dr §6.3.1.3 2

Минимальные значения, конечно, 0 для типа без знака .

unsigned long long b_min = 0;
unsigned long long b_max = -1;
printf("unsigned long long range [%llu %llu]\n", b_min, b_max); 

Обратите внимание, что разборчивые компиляторы будут жаловаться на назначениезначение вне диапазона с b_max = -1;.Используйте ULLONG_MAX.


Где я сделал не так?

Предупреждение "предупреждение: целочисленная константа настолько велика, что она без знака" обусловлена ​​тем, что 18446744073709551615 является целочисленной десятичной константой вне диапазона long long на вашей платформе.Неокрашенные десятичные константы ограничены этим.Добавить U или u.Тогда компилятор рассмотрит unsigned long long.

unsigned long long b = 18446744073709551615u;

Кроме того, нет спецификации C, в которой говорится, что 18446744073709551615 является максимальным значением unsigned long long.Это должно быть минимум .Это может быть больше.Таким образом, присвоение b = 18446744073709551615u может не присвоить значение max .

Как изменить код?

Показано выше

0 голосов
/ 26 апреля 2018

Как указано в rsp, вы можете указать тип литерала с помощью UL и ULL. Но это не приведет к окончательному результату в вашем коде для арифметики.

Значение вашего отпечатка всегда будет 0, потому что

2^64 % 64 = 0 // 64 = 8 byte
2^64 % 32 = 0 // 32 = 4 byte
2^64 % 16 = 0 // 16 = 2 byte

Как вы можете видеть, переменный размер всегда удваивается, поэтому, если вы используете число переноса для 8 байтов, оно просто оборачивает несколько типов в меньшие размеры и дает тот же результат.

sizeof покажет вам правильные значения.

Но обычно вы хотите проверять эти вещи в коде, а не в выводе, чтобы вы могли использовать limits.h, как это предложил Арндт Джонасон.

или вы можете использовать static_assert для проверки во время компиляции.

0 голосов
/ 26 апреля 2018

Вы найдете некоторые полезные определения в <limits.h>.

0 голосов
/ 26 апреля 2018

Когда вы инициализируете num, вы можете добавить "UL" для unsigned long и ULL для unsigned long long.

Например:

unsigned long a = 18446744073709551615UL;
unsigned long long b = 18446744073709551615ULL;

Кроме того, используйте %zu вместо %d, поскольку sizeof return size_t.

Согласно cppreference :

  • целочисленный суффикс, если предоставляется, может содержать одно или оба из следующих значений (если указаны оба, они могут появляться в любом порядке:
    • unsigned-suffix (символ u или символ U)
    • long-suffix (символ l или символ L) или long-long-suffix (последовательность символов ll илипоследовательность символов LL) (начиная с C99)

C стандарт 5.2.4.2.1 Размеры целочисленных типов <limits.h>:

1 Приведенные ниже значения должны быть заменены константными выражениями, подходящими для использования в директивах предварительной обработки #if. Кроме того, за исключением CHAR_BIT и MB_LEN_MAX следующее должно быть заменено выражениями того же типа, что и выражение, являющееся объектом соответствующего типа, преобразованным в соответствии сцелочисленные акции. Их значения, определенные реализацией, должны быть равны или больше по величине (абсолютное значение) показанным с тем же знаком.

0 голосов
/ 26 апреля 2018

Инициализировать числа без знака с -1.Это будет автоматически МАКСИМАЛЬНОЕ значение в C.

#include <stdio.h>
int main(void)
{
    printf("long takes up %d bytes:\n", sizeof(long));
    printf("long long takes up %d bytes:\n", sizeof(long long));

    unsigned long a = -1;
    printf("a = %lu\n", a); 

    unsigned long long b = -1;
    printf("b = %llu\n", b); 

    return 0;
}

Обновление : Изменен код на основе комментариев:)

...