Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.205.56.209] |
|
Сообщ.
#1
,
|
|
|
Всем хай!
Есть такой ( вроде бы ) простейший код на языке С ( С89 ): #include <stdio.h> #include <stdlib.h> int main( void ) { unsigned int a; int b; a = 5; b = -11; printf( "b > a: %d\n\n", b > a ); system( "pause" ); return EXIT_SUCCESS; } хотелось бы пошагово его разобрать на битовом уровне Оговорка: пусть для упрощения писанины типы данных unsigned int и int 2байтовые ( по 16 бит ) ------------------------------------------------------------------------------------------------ в этой строке unsigned int a; резервируется память под переменную a в размере 16 бит ( 2 байта ) в этой строке int b; резервируется память под переменную b в размере 16 бит ( 2 байта ) в этой строке a = 5; 16 бит принимают заданное значение. Тип данных переменной а беззнаковый, т е старший бит участвует a = 00000000 00000101 - двоичное представление в памяти ЭВМ в этой строке b = -11; 16 бит принимают заданное значение. Тип данных переменной b знаковый, т е старший бит участвует и будет равен 1 также отр.числа хранятся в доп.коде, который получается из прямого инвертированием бит + 1 10000000 00001011 --> 11111111 11110100 --> 11111111 11110101 b = 11111111 11110101 - двоичное представление в памяти ЭВМ в итоге a = 00000000 00000101 b = 11111111 11110101 -------------------------- и затем последняя, самая сложная)) строка кода: printf( "b > a: %d\n\n", b > a ); сначала компилятор вычисляет выражение b > a + он замечает, что у них РАЗНЫЕ типы данных. По правилам, заложенным где-то в недрах его он все приводит к беззнаковому типу, т е к типу данных unsigned int. То есть теперь компилятор смотрит на эти биты 11111111 11110101 ( это переменная b ) с тз типа данных unsigned int и это число 2^16 - 11 = 65 525 происходит сравнение: 65 525 > 5 - ну как бы да) это лог. операция и ее результатом является значение TRUE/FALSE. При этом для языка Си FALSE это ТОЛЬКО значение 0, а TRUE - все остальное целочисленное ( даже отр.числа ) при печати стоит модификатор %d, т е давит знаковый целочисленный тип. Что распечатается в ответе? Печатается 1, ну в принципе это логично. Хотя, наверное, могло распечататься любое целое число, не равное 0 ( 0 отдан ТОЛЬКО false ). Но вот всегда в таких ситуациях печатается 1; не 2, не 43, не -5392, а именно 1. Почему? - это небольшой доп. вопрос. ----------------------------------------------------- все ли верно расписал выше или есть какие-то грубые нестыковки? спс. за внимание, надеюсь, не сильно утомил!) |
Сообщ.
#2
,
|
|
|
Цитата FasterHarder @ 10000000 00001011 При переходе от без знакового числа к числу в дополнительном коде бит знака возникает сам в результате инверсии. Его не нужно описывать отдельно. int b = 11 // 0000`0000`0000`1011 b = -b // инверсия 1111`1111`1111`0100 и добавление единицы 1111`1111`1111`0101 - старший разряд без особой обработки стал равен знаку числа. b = -b // инверсия 0000`0000`0000`1010 и добавление единицы 0000`0000`0000`1011 - старший разряд без особой обработки опять стал равен знаку числа. //Тоже самое справедливо для значения 0 b = 0 // 0000`0000`0000`0000 b = -b // инверсия 1111`1111`1111`1111 и добавление единицы 0000`0000`0000`0000 //И для значения 0x8000 b = 0x8000 // 1000`0000`0000`0000 b = -b // инверсия 0111`1111`1111`1111 и добавление единицы 1000`0000`0000`0000 После операции сравнения используется команда записи значения флага в регистр (seta - при сравнении без знаковых/setg - после сравнения знаковых), которая дает значения 0 или 1 в зависимости от операции сравнения. т.е. на вывод поступает именно значение типа bool (0 = false / 1 = true) после операции сравнения. |
Сообщ.
#3
,
|
|
|
Цитата FasterHarder @ Открываем стандарт С99:Но вот всегда в таких ситуациях печатается 1; не 2, не 43, не -5392, а именно 1. Почему? Цитата Никакой магии. 6.3.1.2 Boolean type When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1. |
Сообщ.
#4
,
|
|
|
Dushevny, ответ - бомба!
|
Сообщ.
#5
,
|
|
|
Цитата macomics @ После операции сравнения используется команда записи значения флага в регистр (seta - при сравнении без знаковых/setg - после сравнения знаковых), которая дает значения 0 или 1 в зависимости от операции сравнения. т.е. на вывод поступает именно значение типа bool (0 = false / 1 = true) после операции сравнения. понятно, этого не знал, спс Цитата Dushevny @ Открываем стандарт С99: ну я как бы это того писал, что мол: Цитата FasterHarder @ код на языке С ( С89 ): надо сверить это для С89 но macomics выше пояснил этот момент вроде как... зы: а вообще всех этих приведений надо по максам избегать, т к можно получить трудноуловимые проблемы |
Сообщ.
#6
,
|
|
|
Цитата FasterHarder @ Такого старого под рукой не было. А разве имеет смысл писать, ограничивая себя стандартом 33-летней давности?надо сверить это для С89 Цитата FasterHarder @ Вовсе необязательно. Достаточно просто знать, как они работают и исходник не будет перегружен явными приведениями типов в тех местах, где в них нет необходимости. а вообще всех этих приведений надо по максам избегать, т к можно получить трудноуловимые проблемы |
Сообщ.
#7
,
|
|
|
Цитата Dushevny @ Там то же, только без явного boolевого типа.Такого старого под рукой не было. Цитата Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has type int. ... The == (equal to) and the != (not equal to) operators are analogous to the relational operators except for their lower precedence. Добавлено P.S. Почему делается каст именно к беззнаковому при несовпадении знаковости, ябеспонятия. Но могу выдвинуть две гипотезы. Обе гипотезы сомнительные, так что относитесь к ним как к ИМХО. |