Каков точный диапазон значений для unsigned long? - PullRequest
0 голосов
/ 21 февраля 2019

Я прорабатываю упражнения в книге «Учись С трудным путем».В упражнении 7 читатель просит найти значение, из-за которого диапазон unsigned long превышает.

Измените long на unsigned long и попытайтесь найти число, которое делает его слишком большим.

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

printf("SIZEOF ULONG: %lu", sizeof(unsigned long));

В результате будет напечатано 8.Таким образом, предполагая, что unsigned long будет занимать 64 бита на моей машине, я посмотрел максимальный диапазон на Википедии .

64-бит (слово, двойное слово, длинное слово, длинный длинный, квад, quadword, qword, int64)

  • Без подписи: от 0 до 18,446,744,073,709,551,615

Я ожидал, что объявление unsigned long с указанным выше значением будет компилироваться без предупреждений, пока яувеличьте значение на 1. Однако результат будет другим.компиляция следующей программы выдает предупреждение.

#include <stdio.h>
int main()
{
    unsigned long value = 18446744073709551615;
    printf("SIZEOF ULONG: %lu", sizeof(unsigned long));
    printf("VALUE: %lu", value);
    return 0;
}

bla.c: In function ‘main’:
bla.c:5:27: warning: integer constant is so large that it is unsigned
     unsigned long value = 18446744073709551615;
                           ^~~~~~~~~~~~~~~~~~~~

Так почему же gcc жалуется на большое значение, я думал, что я уже объявил его как unsigned?

Ответы [ 5 ]

0 голосов
/ 21 февраля 2019

Целочисленная константа 18446744073709551615 слишком велика, чтобы ее можно было представить в вашей системе как int, long int или long long int.Компилятор предупреждает вас о том, что он делает его unsigned long long.

Давайте попробуем скомпилировать эту программу вместо этого:

#include <stdio.h>

int main() {
    if (-1 < 18446744073709551615)
        printf("TRUE\n");
    else
        printf("FALSE\n");

    return 0;
}

gcc выдаст предупреждение:

#1 with x86-64 gcc 8.2
<source>: In function 'main':
<source>:7:14: warning: integer constant is so large that it is unsigned
     if (-1 < 18446744073709551615)
              ^~~~~~~~~~~~~~~~~~~~

И вывод программы такой:

TRUE

clang генерирует более явное предупреждение:

#1 with x86-64 clang 7.0.0
<source>:7:14: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
    if (-1 < 18446744073709551615)
             ^

Но вывод программы:

FALSE

Если 18446744073709551615 действительно интерпретируется как беззнаковое, как будто написано 18446744073709551615u или 0xffffffffffffffff, сравнение должно выполняться с использованием арифметики без знака и завершается неудачно, поскольку оба числа имеют одинаковое значение.clang делает то, что говорит, но gcc не делает.

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

Обратите внимание, однако, что вы можете получить максимальное значение любого типа без знака, приведя -1 к этому типу.Вы также можете использовать макросы, определенные в <limits.h>: максимальное значение для типа unsigned long равно ULONG_MAX.

0 голосов
/ 21 февраля 2019

Вам нужен суффикс для целочисленного литерала для значений, который не помещается в long int (или long long int, начиная с C99 и C ++ 11).Любое из следующего будет соответствовать для беззнакового long int:

unsigned long value = 18446744073709551615u;
unsigned long value = 18446744073709551615lu;
unsigned long value = 18446744073709551615ul;

Пожалуйста, смотрите таблицу суффиксов здесь:

https://en.cppreference.com/w/c/language/integer_constant (для C) https://en.cppreference.com/w/cpp/language/integer_literal (для C ++)

0 голосов
/ 21 февраля 2019

Десятичные целочисленные константы имеют тип int, если они вписываются в этот диапазон, в противном случае они имеют тип long или long long.У них нет типа без знака, и если значение находится за пределами этих диапазонов со знаком, вы получите предупреждение.Вам нужно добавить суффикс ul, чтобы константа имела правильный тип.

Существует также гораздо более простой способ получить максимальное значение этого типа, не зная его размера.Просто приведите -1 к этому типу.

unsigned long value = (unsigned long)-1;
0 голосов
/ 21 февраля 2019

Компилятор обрабатывает unsigned long value = 18446744073709551615; в несколько шагов.Прежде чем он сможет инициализировать value значением, он должен прочитать 18446744073709551615 из исходного кода и интерпретировать его.

Цифра 18446744073709551615 в исходном коде стоит сама по себе - на нее не влияют сразутем фактом, что он будет использован для инициализации value.Он обрабатывается в соответствии с правилами стандарта C.

Эти правила говорят, что цифра с десятичными цифрами и без суффикса является либо int, long int, либо long long int, в зависимости от того, что являетсяПервое, что может представлять ценность.Поскольку 18446744073709551615 такой большой, он не подходит ни к одному из этих типов.

Компилятор предупреждает вас, что, поскольку 18446744073709551615 не подходит ни к одному из этих типов, он использует для него тип без знака.В других обстоятельствах это может изменить смысл кода.Однако в этом случае, поскольку значение немедленно используется для инициализации unsigned long, оно будет иметь желаемый эффект.

Чтобы исправить это, вы можете добавить суффикс u, изменив его на 18446744073709551615u.Для десятичного числа с суффиксом u стандарт C говорит, что тип является первым из unsigned int, unsigned long int или unsigned long long int, который может представлять значение.

(Стандарт C продолжаетсясказать, что если значение слишком велико для перечисленных типов, реализация C может представлять его расширенным целочисленным типом или что у него нет типа. Последствия отсутствия типа могут быть интересны для изучения, но это темана вопрос юриста-лингвиста.)

0 голосов
/ 21 февраля 2019

use unsigned long value = 18446744073709551615ul; else 18446744073709551615ul читается как int , а не как long

Если вы хотите узнать количество бит в unsigned long и максимальное значение:

#include <stdio.h>
#include <limits.h>

int main()
{
    printf("number of bits in ULONG: %d\nULONG_MAX = %lu\n",
       sizeof(unsigned long) * CHAR_BIT,
       ULONG_MAX);
    return 0;
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra u.c
pi@raspberrypi:/tmp $ ./a.out
number of bits in ULONG: 32
ULONG_MAX = 4294967295

Да, мои длинные не на 64 битах

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...