2013-07-26 2 views
2

В разделе 7.19.6.1 пункт 8 стандарта C99:ли% с fprintf спецификатор требуется принять Int аргумент

c Если нет l длина модификатора не присутствует, int аргумент преобразуется в unsigned char, и полученный символ записывается.

В секции 7.19.6.1 пункт 9 стандарта C99:

Если какой-либо аргумент не правильный тип для соответствующей спецификации преобразования, поведение не определено.

  • ли функция fprintf требует int аргумента?

Например, будет пропускание unsigned int результата в непредсказуемом поведении:

unsigned int foo = 42; 

fprintf(fp, "%c\n", foo); /* undefined behavior? */ 

Это меня беспокоит, так как реализация может быть определена char как имеющая такое же поведение, как раздел пункт unsigned char (6.2.5 15).

Для этих случаев целая реклама может указывать на то, что char будет promoted to unsigned int on some implementations. Таким образом, оставив следующий код на риск неопределенное поведение на этих реализациях:

char bar = 'B'; 

fprintf(fp, "%c\n", bar); /* possible undefined behavior? */ 
  • ли int переменные и константы буквальным int единственный безопасный способ передать значение fprintf с %c спецификатора?
+1

Ну, вы всегда можете написать 'fprintf (fp,"% c \ n ", 'B');'. –

+1

Ах да, я забыл, что символьные константы имеют тип 'int' в C, не так ли? –

ответ

3

Да, printf с "%c" требует аргумента int - более или менее.

Если аргумент имеет тип, более узкий, чем int, то это будет продвинутый. В большинстве случаев поощрение составляет int, с четко определенным поведением. В очень редком случае, что равнина char является неподписанной и sizeof (int) == 1 (что подразумевает CHAR_BIT >= 16), довод char составляет unsigned int, который может вызывать неопределенное поведение.

Постоянная символа уже имеет тип int, поэтому printf("%c", 'x') четко определен даже на экзотических системах. (Не по теме: В C++ символьные константы имеют тип char.)

Это:

unsigned int foo = 42; 
fprintf(fp, "%c\n", foo); 

строго говоря имеет неопределенное поведение. N1570 7.1.4p1 говорит:

Если аргумент функции имеет тип ... (после продвижения) не ожидаемую функцию с переменным числом аргументов, поведение не определено.

и fprintf Звонок явно работает от этого. (. Благодаря ouah за указание, что выход)

С другой стороны, 6.2.5p6 говорит:

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

и 6.2.5p9 говорит:

Диапазон неотрицательных значений знакового целого типа является поддиапазоном соответствующего типа целого числа без знака, и представление одинакового значения в каждом типе та же.

сноски:

То же требование представления и выравнивания имели в вид, взаимозаменяемости в качестве аргументов функции, возвращать значения из функций, а также члены профсоюзов.

Сноска говорит, что аргументы функции типов int и unsigned int являются взаимозаменяемыми, до тех пор, пока значение находится в пределах диапазона представимых обоих типов. (Для типичной 32-битной системы, это означает, что значение должно быть в диапазоне от 0 до 2 -1; int значения от -2 -1, а unsigned int значения от 2 до 2 -1, находятся за пределами диапазона другого типа, и не являются взаимозаменяемыми.)

Но сноски в стандарте C являются ненормативного. Они, как правило, предназначены для уточнения требований, изложенных в нормативном тексте, а не для введения новых требований. Но в этом нормативном тексте просто говорится, что соответствующие подписанные и неподписанные типы имеют одинаковое представление, которое не обязательно обязательно подразумевают, что они передаются так же, как аргументы функции. В принципе, компилятор может игнорировать эту сноску и, например, передавать int и unsigned int аргументы в разных регистрах, что делает fprintf(fp, "%c\n", foo); неопределенным.

Но на практике нет никакой возможности для реализации игры такого рода, и вы можете положиться на fprintf(fp, "%c\n", foo); для работы, как ожидалось. Я никогда не видел и не слышал о реализации, где это не сработало.

Лично я предпочитаю не полагаться на это. Если бы я писал этот код, я хотел бы добавить явное преобразование, с помощью актеров, просто так эти вопросы не возникают в первую очередь:

unsigned int foo = 42; 
fprintf(fp, "%c\n", (int)foo); 

Или я сделаю foo в int в первом место.

+0

Когда вы заявляете, что мой пример «на самом деле имеет четко определенное поведение», вы говорите, что он определен для моего конкретного значения «42», а, возможно, не определено для значений вне диапазона, представляемых 'int'? –

+1

@VilhelmGray: Да. Он хорошо определен (если мы делаем вид, что сноска является нормативной) тогда и только тогда, когда значение имеет диапазоны как 'int', так и' unsigned int'. –

+1

@ KeithThompson C также говорит, что размер и выравнивание 'unsigned int' и' int' одинаковы в * p6) «Для каждого из знаковых целочисленных типов существует соответствующий (но другой) целочисленный тип без знака [.. ,], который использует тот же объем памяти (включая информацию о знаке) и имеет те же требования к выравниванию »* Хотя, вероятно, нет возможности использовать' unsigned int', это технически UB, потому что это явно нарушает 7.1.4p1 * «Если аргумент функции имеет [...] тип (после продвижения), не ожидаемый функцией с переменным числом аргументов, поведение не определено »* – ouah

5

%c спецификация преобразования для fprintf требует int аргумент. Значение должно быть типа int после ставок по умолчанию..

unsigned int foo = 42; 
fprintf(fp, "%c\n", foo); 

неопределенное поведение: foo должен быть int.

char bar = 'B'; 
fprintf(fp, "%c\n", bar); 

не определено поведение: bar способствует (аргумент по умолчанию акции), чтобы, как intfprintf является функцией VARIADIC.

EDIT: быть справедливым, есть еще некоторые очень редкие реализаций, где оно может быть определено поведение.Например, если char является неподписанным типом, причем не все значения char, представляемые в int (например, в this implementation), продвижение по умолчанию по умолчанию выполняется до unsigned int.

+0

Я думаю, что OP особенно беспокоился о 'char' unsigned и ширине' int', и в этом случае 'bar' продвигается до' unsigned int'. –

+0

@ouah Не было бы * аргументов по умолчанию аргументов * для 'char' падения в« целых рекламных акциях »выполняются по каждой категории аргументов ** в разделе 6.5.2.2 ** в пункте 6? –

+0

@PascalCuoq Я могу добавить исправление для этого – ouah

Смежные вопросы