Может ли разница типов между константами 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.