Когда шестнадцатеричное значение «0x000000a1» присвоено (со знаком) char, char равен «0xffffffa1». Кто-нибудь может объяснить это странное поведение?
void main(){
char testVar = 0x000000a1;
printf("%x \n",testVar); //prints ffffffa1
printf("%d \n",testVar); //prints -95
}
Он работает так, как и ожидалось, когда вы инициализируете беззнаковый символ.
void main(){
unsigned char testVar = 0x000000a1;
printf("%x \n",testVar); //prints a1
printf("%d \n",testVar); //prints 161
}
также работает должным образом, когда вы назначаете значение в пределах ограничения ASCII 127 (или 0x7f)
void main(){
unsigned char testVar = 0x7f;
printf("%x \n",testVar); //prints 7f
printf("%d \n",testVar); //prints 127
}
что я понимаю теперь, задав вопрос:
Обратите внимание, что void main() действует только в Windows (поскольку в документах Microsoft это допустимо). Везде main() возвращается int. См. Что должна возвращать функция main() в C и C++? Кроме того, печатать пробел перед новой строкой не рекомендуется. Конечные пробелы должны быть для вас анафемой как в исходном коде, так и в результатах.
ОК, я думаю, теперь я понял, поправьте меня, если я ошибаюсь: первый бит переменной char является флагом, если значение отрицательное (1000 0000 будет отрицательным значением), теперь, когда char расширяется до подписанного int для оператор printf расширяет символ в зависимости от того, является ли символ отрицательным или нет. Я предполагаю, что когда вы явно указываете, что char не имеет знака, printf больше не распознает первый бит как флаг отрицательного значения и поэтому расширяет переменную нулями.
нет, это бит значения, а не флаг, хотя он называется битом знака и может использоваться для проверки знака. В современных процессорах отрицательные значения представлены как дополнение до двух
char всегда имеет длину один байт, в противном случае ваше понимание верно.
Недавно кто-то задал аналогичный вопрос: char * vs unsigned char *





Вы не можете присвоить 0x000000a1 символу, поскольку длина символа составляет всего 2 байта. Вы назначаете только часть a1.
char по определению всегда имеет размер 1 байт. (Однако в экзотических системах он может иметь более 8 бит.) Ключевым моментом здесь является то, что char имеет подпись, определяемую реализацией: он может быть как подписанным, так и беззнаковым, в зависимости от компилятора. Символ по умолчанию подписан или не подписан? Судя по всему в вашем случае это подписано.
Количество нулей перед значением не имеет ни малейшего значения и не влияет на тип. Все, что они делают, это обманывают программиста, думая, что они имеют какой-то смысл.
Первый бит знакового значения указывает, является ли оно отрицательным или нет (1000 0000 является отрицательным и равно -128. 0111111 не является отрицательным и равно 127).
Да, если это MSB.
То, что происходит, когда вы ставите 0xa1 на signed char, также зависит от компилятора. В основных системах это приведет к отрицательному десятичному значению с двоичным дополнением.
или по какой-то причине printf необходимо расширить переменную char до int, прежде чем она выведет значение.
-95 — это вариативная функция (переменное количество аргументов), и для этих функций существует специальное правило неявного повышения типа, называемое «продвижение аргументов по умолчанию». При передаче небольшого целочисленного типа, такого как printf или char, в вариативную функцию, он всегда неявно преобразуется в short. (И при передаче int он будет повышен до float.)
когда printf преобразует знаковый символ в int, он распознает, когда символ отрицательный, и, следовательно, сохраняет отрицательное значение, расширяя его с помощью 1 вместо 0.
Правильный. Во время этой акции, если ваш исходный тип был подписан и имеет отрицательное значение, это учитывается и знак сохраняется, так называемое «расширение знака». Таким образом, в двоичном представлении вещей вместо (со знаком) double 0xa1 = -95 вы получаете char 0xffffffa1 = все еще -95.
Затем вы лжете printf, сообщив ему, что он ожидает параметр int. Строго говоря, это неопределенное поведение, но любой разумный компилятор преобразует %x в unsigned int, и это четко определенное преобразование, в результате чего у вас останется 0xffffffa1, но теперь это беззнаковое представление, поэтому оно равно десятичному значению 4294967201.
У
0xA1установлен старший бит, поэтому, когда (со знаком) значениеcharпреобразуется вintпри передаче вprintf(), оно расширяется по знаку и печатается как отрицательное число (-95). Это нормально и вполне ожидаемо. Значения 0x00..0x7F являются положительными, а 0x80..0xFF отрицательны (со знаком)char.