2013-04-01 2 views

ответ

31

возвещать ch в

unsigned char ch = 212 ; 

И ваша Printf будет работать.

+9

Даже с 'ch' изменен на' беззнаковое char', поведение кода не определено стандартом C. Это связано с тем, что 'unsigned char' продвигается до' int' (в обычных реализациях C), поэтому 'int' передается' printf' для спецификатора '% u'. Однако '% u' ожидает' unsigned int', поэтому типы не совпадают, а стандарт C не определяет поведение. –

+2

Ваш комментарий неверен. В стандарте C11 указано, что спецификатор преобразования должен быть того же типа, что и функция 'argument', а не продвинутый тип. Этот пункт также специально рассматривается в описании модификатора длины hh: «аргумент будет продвигаться в соответствии с целыми рекламными акциями, но его значение должно быть преобразовано в подписанный символ или без знака перед печатью» –

+0

Работает только после явного приведения в 'unsigned int' при передаче в' prtinf() '. Добавление -std = c11 в команду gcc-4.8.4 для принудительного применения стандарта не повлияло. – ypx

28

Это потому, что в этом случае в вашей системе подписан код char*. Когда это происходит, данные становятся расширенными во время конверсий по умолчанию при передаче данных функции с переменным числом аргументов. Так как 212 больше, чем 0х80, он рассматривается как негативные, %u интерпретирует число как большое положительное число:

212 = 0xD4 

Когда по знаку, FF s предварительно затрачиваемого на ваш номер, так что становится

0xFFFFFFD4 = 4294967252 

который является номером, который печатается.

Обратите внимание, что это поведение специфично для вашей реализации. В соответствии со спецификацией C99, все char типы назначен (подпись) int, поскольку int может представлять все значения из char, знаком или без знака:

6.1.1.2: Если int может представлять все значения первоначальный тип, значение преобразуется в int; в противном случае он преобразуется в unsigned int.

В результате прохождения int к спецификатору формата %u, который ожидает unsigned int.

Чтобы избежать неопределенного поведения в вашей программе, добавить явные приведения типов следующим образом:

unsigned char ch = (unsigned char)212; 
printf("%u", (unsigned int)ch); 


* В целом, стандарт оставляет знаковость char до реализации. См. this question для более подробной информации.

+1

Этот ответ путается и неточен.Предложения о расширении знака и обработке 212 представлены без контекста, не объясняя, где они применяются (более раннее предложение применяется к более поздней операции, целая продвижение символа 'char', когда оно используется в качестве аргумента, в то время как более позднее предложение применяется к более ранняя операция, инициализация 'char' с помощью' int'). –

+1

Утверждение, что 212 считается отрицательным, потому что оно больше 0x80, является ложным. Во-первых, инициализация подписанного 'char' с 212 вызывает переполнение целых чисел в большинстве реализаций C, поэтому поведение не определено. Во многих реализациях C это приводит к усечению представления двоичного представления от 212 до восьми бит, что заставляет биты интерпретироваться как отрицательное значение, потому что бит 0x80 установлен, а не потому, что начальное значение больше 0x80 (контрпримеры включают 0x80 и 0x100). –

+1

После инициализации 'char' он используется как аргумент' printf'. Выполняются целые рекламные акции, в результате чего отрицательный 'int' передается' printf'. Опять же, многие реализации C используют два дополнения, поэтому расширение знака выполняется, как говорится в этом ответе. Преобразование значения в 'unsigned' в этой точке даст большое положительное число. Однако этот ответ не объясняет, что фактическое поведение не определено стандартом C, потому что 'int' передается для спецификатора'% u', который ожидает 'unsigned int'. –

2

Диапазон знаков от 127 до -128. Если вы назначили 212, ch-магазины -44 (212-128-128) не 212. Так что, если вы попытаетесь напечатать отрицательное число как unsigned, вы получите (MAX-значение unsigned int) -abs (number), который в этом случае является 4294967252

так что, если вы хотите хранить 212, как в гл единственное, что вы можете сделать, это объявить ч, как

unsigned char ch; 

теперь диапазон ч составляет от 0 до 255.

+2

«Диапазон диапазона от 127 до -128». - Нет, диапазон определяется реализацией. –

+0

@Jim Что вы имеете в виду? – banarun

+1

Я имею в виду то, что я сказал ... было ясно. Символ не обязательно обязательно 8 бит, пусть вместе обязательно подписан. –

9

В этом коде есть две ошибки. Во-первых, в большинстве реализаций C с подписанным char происходит переполнение в char ch = 212, потому что 212 не подходит в 8-разрядной подписанной char, а стандарт C не определяет поведение при переполнении целых чисел. Вместо этого она должна быть:

unsigned char ch = 212; 

Во-вторых, в printf("%u",ch), ch будет повышен до int в нормальных реализациях C. Однако спецификатор %u ожидает unsigned int, а стандарт C не определяет поведение при передаче неправильного типа. Вместо этого она должна быть:

printf("%u", (unsigned) ch); 
+0

Я бы предложил использовать static_cast вместо старого стиля. – ShitalShah

+1

@ShitalShah: вопрос помечен C, а не C++. C не имеет оператора static_cast. –

+0

Ах .. не видел этого. – ShitalShah

1

Поскольку char по умолчанию signed заявил, что означает, что диапазон переменной

-127 до +127>

ваше значение переполнена. Чтобы получить желаемое значение, вам необходимо объявить модификатор unsigned. (unsigned) Диапазон модификатора заключается в следующем:

0 to 255 

, чтобы получить диапазон любого типа данных следить за процессом 2^bit пример char 8 битовой длины, чтобы получить свой диапазон просто 2 ^(power) 8.

1

В случае, если вы не можете изменить декларацию по какой-либо причине, вы можете сделать:

char ch = 212; 
printf("%d", (unsigned char) ch); 
Смежные вопросы