Может ли sizeof (int) быть 1 в размещенной реализации? - PullRequest
41 голосов
/ 05 октября 2010

Я считаю, что реализация C не может удовлетворять спецификации некоторых stdio функций (в частности, fputc / fgetc), если sizeof(int)==1, поскольку int должна содержать любое возможное значение unsigned char или EOF (-1). Это рассуждение правильно?

(Очевидно, sizeof(int) не может быть 1, если CHAR_BIT равно 8, из-за минимального требуемого диапазона для int, поэтому мы неявно говорим только о реализациях с CHAR_BIT>=16, например DSP, где типичные реализации будет автономной реализацией, а не размещенной реализацией, и, следовательно, не будет обязательным для предоставления stdio.)

Редактировать : После прочтения ответов и ссылок на некоторые ссылки, некоторые мысли о том, как может быть допустимо для размещенной реализации иметь sizeof(int)==1:

Сначала несколько цитат:

7.19.7.1 (2-3):

Если индикатор конца файла для входного потока, на который указывает поток, не установлен и следующий символ присутствует, функция fgetc получает этот символ как неподписанный char преобразуется в int и перемещает соответствующий индикатор позиции файла для поток (если определен).

Если установлен индикатор конца файла для потока или если поток находится в конце файла, индикатор конца файла для потока установлен, и функция fgetc возвращает EOF. В противном случае Функция fgetc возвращает следующий символ из входного потока, на который указывает поток. Если происходит ошибка чтения, устанавливается индикатор ошибки для потока и функция fgetc возвращает EOF.

7.19.8.1 (2):

Функция fread считывает в массив, на который указывает ptr, до nmemb элементов чей размер определяется размером от потока, на который указывает поток. Для каждого объект, вызовы размера выполняются для функции fgetc и результаты сохраняются в порядке читай, в массиве unsigned char точно наложение объекта. Позиция файла индикатор для потока (если он определен) увеличивается на количество успешно прочитанных символов.

Мысль:

  • Считывание unsigned char значений вне диапазона int может просто иметь undefined определяемое реализацией поведение в реализации. Это особенно тревожно, так как это означает, что использование fwrite и fread для хранения бинарных структур (которое, в то время как это приводит к непортативным файлам, должно быть операцией, которую вы можете выполнить переносимо в любой отдельной реализации) может показаться работающим, но молча провалиться по существу всегда приводит к неопределенному поведению . Я согласен с тем, что реализация может не иметь пригодной для использования файловой системы, но гораздо сложнее признать, что реализация может иметь файловую систему, которая автоматически вызывает назальных демонов, как только вы попытаетесь ее использовать, и не сможете определить, что она непригодна для использования. Теперь, когда я понимаю, что поведение определяется реализацией, а не неопределенно, это не так тревожно, и я думаю, что это может быть допустимой (хотя и нежелательной) реализацией.

  • Реализация sizeof(int)==1 может просто определить файловую систему как пустую и доступную только для чтения. Тогда приложение не сможет считывать любые данные, записанные им самим, только с устройства ввода на stdin, которое может быть реализовано так, чтобы выдавать только положительные значения char, которые соответствуют int.

Редактировать (снова): Из Обоснования C99, 7.4:

EOF традиционно равен -1, но может быть любым отрицательным целым числом и, следовательно, отличается от любого допустимого кода символа .

Это, кажется, указывает на то, что sizeof(int) не может быть 1 или, по крайней мере, так было задумано комитетом.

Ответы [ 8 ]

24 голосов
/ 05 октября 2010

Реализация может соответствовать требованиям интерфейса для fgetc и fputc, даже если sizeof(int) == 1.

Интерфейс для fgetc говорит, что возвращает символ, прочитанный как unsigned char конвертируется в int.Нигде не говорится, что это значение не может быть EOF, хотя очевидно, что действительные значения «обычно» возвращают положительные значения.Конечно, fgetc возвращает EOF при ошибке чтения или конце потока, но в этих случаях также устанавливается индикатор ошибки файла или индикатор конца файла (соответственно).

Точно так же нигде не выполняетсяон говорит, что вы не можете передать EOF в fputc, если это совпадает со значением unsigned char, преобразованным в int.

Очевидно, программист должен быть оченьосторожно на таких платформах.Это может не делать полную копию:

void Copy(FILE *out, FILE *in)
{
    int c;
    while((c = fgetc(in)) != EOF)
        fputc(c, out);
}

Вместо этого вам придется сделать что-то вроде (не проверено!):

void Copy(FILE *out, FILE *in)
{
    int c;
    while((c = fgetc(in)) != EOF || (!feof(in) && !ferror(in)))
        fputc(c, out);
}

Конечно, платформы, на которых вы будете иметьнастоящие проблемы - это те, где sizeof(int) == 1 и преобразование из unsigned char в int не является инъекцией.Я считаю, что это обязательно будет иметь место на платформах, использующих знак и величину или дополняющих для представления целых чисел со знаком.

10 голосов
/ 05 октября 2010

Я помню тот же самый вопрос на comp.lang.c около 10 или 15 лет назад.Ища его, я нашел более актуальное обсуждение здесь:

http://groups.google.de/group/comp.lang.c/browse_thread/thread/9047fe9cc86e1c6a/cb362cbc90e017ac

Я думаю, что есть два результирующих факта:

(a) Могут быть реализациигде строгое соответствие невозможно.Например, sizeof (int) == 1 с отрицательными значениями из одного дополнения или величины знака или битами заполнения в типе int, т. Е. Не все беззнаковые значения char могут быть преобразованы в действительное значение int.

(b)Типичная идиома ((c=fgetc(in))!=EOF) не переносима (за исключением CHAR_BIT == 8), поскольку EOF не обязательно должен быть отдельным значением.

5 голосов
/ 26 июня 2011

Я не верю, что стандарт C напрямую требует, чтобы EOF отличался от любого значения, которое может быть прочитано из потока.В то же время, кажется, само собой разумеющимся, что это будет.Некоторые части стандарта имеют противоречивые требования, которые, я сомневаюсь, могут быть выполнены, если EOF - это значение, которое можно прочитать из потока.

Например, рассмотрим ungetc.С одной стороны, спецификация гласит (§7.19.7.11):

Функция ungetc помещает символ, указанный в c (преобразованный в беззнаковый символ), обратно во входной поток, на который указывает stream.Задержанные символы будут возвращены последующими чтениями в этом потоке в обратном порядке их нажатия.[...] Гарантируется один символ обратного хода.

С другой стороны, он также говорит:

Если значение c равно значению макроса EOFоперация завершается неудачно, а входной поток остается неизменным.

Итак, если EOF - это значение, которое можно прочитать из потока, и (например) мы действительно читаем из потока и сразу используемungetc чтобы вернуть EOF обратно в поток, мы получаем загадку: вызов "гарантированно" завершается успешно, но также явно требуется сбой.

Если кто-то не может найти способ согласовать эти требования, яУ меня остались значительные сомнения относительно того, может ли такая реализация соответствовать.

В случае, если кому-то все равно, N1548 (текущий проект нового стандарта C) сохраняет те же требования.

3 голосов
/ 05 октября 2010

Не будет ли достаточно, если номинал char, который разделяет битовую комбинацию с EOF, будет определен как бессмысленный? Например, если CHAR_BIT равен 16, но все разрешенные значения занимают только 15 младших значащих битов (предположим, что 2-кратное дополнение для представления int со знаком знака). Или все, представимое в char, должно иметь значение как таковое? Признаюсь, я не знаю.

Конечно, это будет странный зверь, но мы позволяем нашему воображению идти сюда, верно?

Р .. убедил меня, что это не сработает. Поскольку размещенная реализация должна реализовывать stdio.h, и если fwrite должен иметь возможность прикреплять целые числа на диске, то fgetc может вернуть любой битовый шаблон, который поместится в char, и это не должно мешать возвращению EOF. QED.

2 голосов
/ 05 октября 2010

Я думаю, что вы правы. Такая реализация не может отличить допустимое значение знака без знака от EOF при использовании fgetc / fputc в двоичных потоках.

Если есть такие реализации ( этот поток , кажется, предполагает, что есть), они не строго соответствуют. Возможно иметь автономную реализацию с sizeof (int) == 1.

Отдельно стоящая реализация (C99 4) должна поддерживать только функции стандартной библиотеки, указанные в следующих заголовках: , , , , , и . (Примечание: нет ). В любом случае автономная работа может иметь больше смысла для DSP или другого встроенного устройства.

2 голосов
/ 05 октября 2010

Я не очень знаком с C99, но я не вижу ничего, что говорит, что fgetc должен выдавать полный диапазон значений char. Очевидный способ реализовать stdio в такой системе - поместить 8 бит в каждый char независимо от его емкости. Требование EOF составляет

EOF

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

Ситуация аналогична wchar_t и wint_t. В 7.24.1 / 2-3, определяющих wint_t и WEOF, в сноске 278 говорится

wchar_t и wint_t могут быть одного целого типа.

, что, по-видимому, гарантирует, что "мягкой" проверки диапазона достаточно, чтобы гарантировать, что *EOF не входит в набор символов.

Edit:

Это не разрешит двоичные потоки, поскольку в таком случае fputc и fgetc не требуются для выполнения преобразования. (7.19.2 / 3) двоичные потоки не являются обязательными; только их отличие от текстовых потоков не является обязательным. Таким образом, кажется, что это делает такую ​​реализацию несовместимой. Тем не менее, он по-прежнему будет вполне пригоден для использования, если только вы не попытаетесь записать двоичные данные за пределы 8-битного диапазона.

1 голос
/ 06 октября 2010

Компилятор TI C55x, который я использую, имеет 16-битный символ и 16-битный тип int, а включает стандартную библиотеку. Библиотека просто использует восьмибитный набор символов, так что при интерпретации символа как символа значение> 255 не определяется; и при записи в 8-битное потоковое устройство отбрасываются наиболее значимые 8 битов: например, при записи в UART только младшие 8 битов передаются в регистр сдвига и выводятся.

1 голос
/ 05 октября 2010

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

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