Может ли разница типов между константами 32768 и 0x8000 иметь значение?

В стандарте указано, что шестнадцатеричные константы, такие как 0x8000 (больше, чем подходит для целого числа со знаком), являются беззнаковыми (как и восьмеричные константы), тогда как десятичные константы, такие как 32768, подписаны долго. (Точные типы предполагают 16-битное целое число и 32-разрядную длину.) Однако в обычных средах C оба будут иметь одинаковое представление в двоичном формате 1000 0000 0000 0000. Возможна ли ситуация, когда эта разница действительно приводит к другому результату? Другими словами, возможна ли ситуация, когда это различие имеет значение вообще?

Ответы

Ответ 1

Да, это может иметь значение. Если ваш процессор имеет 16-разрядный int и 32-разрядный тип long, 32768 имеет тип long (поскольку 32767 является наибольшим положительным значением, установленным в 16-разрядном значении int), тогда как 0x8000 (так как он также считается для unsigned int), все еще подходит для 16-разрядного unsigned int.

Теперь рассмотрим следующую программу:

int main(int argc, char *argv[])
{
  volatile long long_dec = ((long)~32768);
  volatile long long_hex = ((long)~0x8000);

  return 0;
}

Когда 32768 считается long, отрицание инвертирует 32 бита, что приводит к представлению 0xFFFF7FFF с типом long; литой излишний. Когда 0x8000 считается unsigned int, отрицание инвертируется 16 бит, что приводит к представлению 0x7FFF с типом unsigned int; тогда листинг будет равен нулю - до значения long 0x00007FFF. Посмотрите на H & S5, раздел 2.7.1 стр. 24ff.

Лучше всего увеличить константы с помощью U, UL или L.

Ответ 2

На 32-битной платформе с 64-битным long, a и b в следующем коде будут разные значения:

int x = 2;
long a = x * 0x80000000; /* multiplication done in unsigned -> 0           */
long b = x * 2147483648; /* multiplication done in long     -> 0x100000000 */

Ответ 3

Еще одно исследование еще не указано: сравните (с операторами большего или меньшего размера) -1 с 32768 и до 0x8000. Или, если на то пошло, попробуйте сравнить каждое из них для равенства с переменной "int", равной -32768.

Ответ 4

Предполагая, что int - 16 бит, а long - 32 бита (что на самом деле довольно необычно в наши дни; int чаще всего 32 бита):

printf("%ld\n", 32768);  // prints "32768"
printf("%ld\n", 0x8000); // has undefined behavior

В большинстве контекстов числовое выражение будет неявно преобразовано в соответствующий тип, определяемый контекстом. (Это не всегда тип, который вы хотите.) Это не относится к нефиксированным аргументам для переменных функций, таких как любой аргумент одной из функций *printf(), следующих за строкой формата.

Ответ 5

Разница была бы в том, что если бы вы попытались добавить значение в 16-битный int, он бы не смог этого сделать, потому что он превысил границы переменной, тогда как если бы вы использовали 32-битный длинный, вы могли бы добавить любые число, которое меньше 2 ^ 16.