Intereting Posts
почему я не могу использовать частичную инициализацию структуры для malloced struct в C Преобразование двухзначного числа в слова с использованием оператора switch Двоичная печать не работает в C Быстрый метод копирования памяти с переводом – ARGB в BGR разглаживающий тип-караульный указатель нарушит правила строгого сглаживания malloc-ating multidimensional array в функции Как я могу применить __attribute __ ((aligned (32))) к int *? feof обнаружения ложного конца файла Использование случайных чисел с графическими процессорами Как связать определенную версию разделяемой библиотеки в make-файле без использования LD_LIBRARY_PATH? C: зачем печатать нулевой символ с печатью% s “(null)”? в чем разница между struct {0} и memset 0 использование вложенных команд printf, дающих странный вывод Возможно ли убить команду, запущенную с использованием системы api в C? Если нет альтернатив? Простая функция тайм-аута

Неявное смешение преобразования между подписанным и неподписанным при чтении книги K & R

Я изучаю язык c, используя книгу K & R. Во второй главе книги автор говорит о неявной конверсии. Там книга говорит об этом:

Правила конверсии более сложны, когда задействованы неподписанные операнды. Проблема в том, что сравнения между подписанными и неподписанными значениями зависят от машины, поскольку они зависят от размеров различных целых типов. Например, предположим, что int 16 бит и длиной 32 бит. Тогда -1L 1UL, потому что -1L повышается до unsigned long и, следовательно, оказывается большим положительным числом.

Я пробовал код ниже в двух разных сценариях:

  1. скомпилирован на платформе x86 64 бит и выполнен. Где sizeof(-1L) -> 8байт и sizeof(1U) -> 4 байта
  2. скомпилирован на платформе x86 32bits и выполнен. Где sizeof(-1L) sizeof(1U) -> 4 байта и sizeof(1U) -> 4 байта

Код:

 int main() { if(-1L > 1U) printf("true"); else printf("false"); return 0; } 

Результаты, достижения:

  1. x86 64bits: false
  2. x86 32bits: true

поэтому я получаю два разных ОП в каждом случае.

Как утверждает автор, для двух разных форматов данных один из них – 16, а другой 32, он хорош в моем случае x86-64.

Но я не могу понять, почему во втором случае для 32 бит, я становлюсь true . Поскольку автор говорит, что unsigned int продвигается до signed long int , если это так, то оба должны быть 4 байта в ширину, тогда почему это печатает true вместо false ? Поскольку сейчас оба должны быть signed long .

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

Я понимаю, что -1 хранится как дополнение двух, т.е. 0xFFFFFFFF > 0x1 поэтому во втором случае это должно быть true .

Но это объяснение противоречит 1-му случаю.

Пожалуйста, поправьте меня, если я ошибаюсь, поскольку я новичок в неявной конверсии.

Может кто-нибудь объяснить это поведение?

позволяет сначала объяснить систему рангов

 6.3.1 Arithmetic operand(c99 standard) A) The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision(more bytes higher precision higher rank) B) The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char. C) The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type, if any. (in other words if your system unsigned int is 32bits and your int is 32bits then the ranks of these are the same.) 

приведенное выше объясняет ранг.

теперь приближается к арифметическим преобразованиям.

 6.3.1.8 Usual arithmetic conversions (c99 standard) 1)If both operands have the same type, then no further conversion is needed. 2)Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.(similar to 1) 3)Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type. 4)Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type 5)Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type. 

2), скомпилированный на платформе x86 32bits и выполненный. Где sizeof (-1L) -> 4 байта и sizeof (1U) -> 4 байта

в вашем случае посмотрите на инструкцию 3 & C. значение unsigned (4 байта) имеет ранг, равный значению (4btyes), поэтому одинарное значение преобразуется в значение без знака, когда это происходит, бит знака делает это похожим на чрезвычайно большое значение. -1L> 1U поэтому верно

1) скомпилирован на платформе x86 64 бит и выполнен. Где sizeof (-1L) -> 8байт и sizeof (1U) -> 4 байта

в этом случае ранг без знака меньше ранга одинарного значения. посмотрите на 4). целое число со знаком (8 байтов) может представлять любое значение без знака 4 байта. поэтому значение unsigned 4byte преобразуется в значение со знаком (это будет сохранять бит знака, бит знака равен 0)

поэтому -1L> 1U является ложным

Но им не удалось понять, почему во втором случае в 32 бит его OP -> true. Как говорит автор, unsigned int продвигается до подписанного long int, если так, тогда оба имеют ширину в 4 байта, поэтому его печать верна вместо false.? так как сейчас обе подписаны долго.

Автор говорит, что если int и long имеют разный размер, то unsigned int продвигается до signed long .

Если int и long имеют одинаковый размер, то long слишком мал, чтобы удерживать все значения unsigned int и поэтому оба они преобразуются в unsigned long .

Для двоичных арифметических и реляционных операторов:

Если любой из операндов имеет тип long double, другой операнд преобразуется в длинный двойной. В противном случае, если любой операнд имеет тип double, другой операнд преобразуется в double. В противном случае, если любой операнд имеет тип float, другой операнд преобразуется в float. В противном случае интегральные рекламные акции выполняются на обоих операндах.

(Интегральное продвижение: в выражении везде, где может использоваться int или unsigned int, может использоваться символ char, короткий int или int bit-field или их подписанные или неподписанные варианты или тип enums. Если int может представляют все значения исходного типа, значение преобразуется в int, в противном случае оно преобразуется в unsigned int.)

Затем, если любой из операндов имеет тип unsigned long int, другой операнд преобразуется в unsigned long int. В противном случае, если один операнд имеет тип long int, а другой имеет тип unsigned int, если long int может представлять все значения unsigned int, операнд типа unsigned int преобразуется в long int; если длинный int не может представлять все значения unsigned int, оба операнда преобразуются в unsigned long int. В противном случае, если любой операнд имеет тип long int, другой операнд преобразуется в long int. В противном случае, если любой из операндов имеет тип unsigned int, другой операнд преобразуется в unsigned int. В противном случае оба операнда имеют тип int.

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

(В приведенном выше описании отсутствует тип unsigned long long int и long long it , но правила в основном одинаковы.)

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

-> if one operand has type long int and the other has type unsigned int,

-> if a long int can represent all values of an unsigned int the operand of type unsigned int is converted to long int;

-> if a long int cannot represent all the values of an unsigned int, both operands are converted to unsigned long int.

Таким образом, сверху one operand has type long int ie -1L а the other has type unsigned int ie 1U

предположим, что sizeof -1L —> 8byte а sizeof 1U – 4 byte

0X0000-0XFFFFF values can be represented using in long int whose sizeof is 8 byte

поэтому в этом случае long int can represent all values of an unsigned int т. е. используя 8byte —>, он может представлять все значения unsigned int 1U .

поэтому —-> здесь operand of type unsigned int is converted to long int —> -1L > 1U --> is false

следующий 2-й случай

if a long int cannot represent all the values of an unsigned int

т.е. sizeof -1L -->4byte и -1L -->4byte 1U -->4byte

здесь long int не может представлять все значения, то есть используя 4 байта -> он cannot represent все значения unsigned int 1U. поэтому оба операнда converted to unsigned long int

-1L кажется большим значением, так как теперь он без знака сравнивается с 1U.

ie---->0xFFFFFFFF > 0x1 ---> its true