Чар подписан или не подписан по умолчанию?

158

В книге «Полная справка о С» упоминается, что char по умолчанию она не подписана.

Но я пытаюсь проверить это с помощью GCC, а также Visual Studio. Это принимает как подписано по умолчанию.

Который правильный?

C Learner
источник
5
Единственный справочник C, которому я доверяю, - это "C: Справочное руководство" Harbison & Steele ( careferencemanual.com ). Конечно, стандарт - это последнее слово, но он не очень читабелен и дает лишь малейшую информацию о предстандартном и обычном (то есть, POSIX) использовании, которые находятся за пределами стандарта. Harbison & Steele довольно читабелен, детален и, вероятно, более точен, чем большинство ссылок. Однако это также не учебник, поэтому, если вы находитесь на начальных этапах обучения, вам, вероятно, не стоит прыгать.
Майкл Берр
15
Я думаю, что книга, которую вы читаете, называется C: The Complete Reference , написанная Гербертом Шильдтом. Из обзора этой книги ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): я не собираюсь рекомендовать эту книгу (слишком многие из вас придают слишком большое значение моему мнению), но Я не думаю, что это заслуживает того же осуждения, которое было законно брошено на некоторые другие его работы. Как говорит Майкл, гораздо лучше справиться с Harbison & Steele .
Алок Сингхал
Мои два цента здесь: Потому что charмогут быть без знака, как правило, использовать intдля чтения значения с использованием getchar(), которое может вернуть EOF. EOFобычно определяется как -1или другое отрицательное значение, сохранение unsignedкоторого не является тем, что вы хотите. Вот декларация: extern int getchar();Кстати, эта рекомендация также взята из книги "C: Справочное руководство".
Максим Четруска
6
Единственная ссылка C, которой я доверяю, - это ISO / IEC 9899: 2011 :-)
Джефф
3
@MaxChetrusca хороший совет, но плохое обоснование: даже для подписанного charслучая вам придется использовать intдля хранения возвращаемого значения.
Антти Хаапала

Ответы:

204

Книга не права. Стандарт не определяет, является ли обычный charподписанным или неподписанным.

На самом деле, стандарт определяет три различных типа: char, signed char, и unsigned char. Если вы, #include <limits.h>а затем посмотрите CHAR_MIN, вы можете узнать, charявляется ли значение равным signedили unsigned(если CHAR_MINоно меньше 0 или равно 0), но даже тогда эти три типа различны. в отношении стандарта.

Обратите внимание, что charэто особенный способ. Если вы объявляете переменную, так как intона на 100% эквивалентна объявлению ее как signed int. Это всегда верно для всех компиляторов и архитектур.

Алок Сингхал
источник
1
@Alok: то же самое не верно для некоторых других типов данных, например, intозначает signed intвсегда, верно? Кроме charкаких других типов данных есть такая же путаница C?
Lazer
8
@eSKay: да, charэто единственный тип, который может быть подписан или не подписан. intэквивалентно, signed intнапример.
Алок Сингхал,
28
Есть истерическая, э-э, историческая причина этого - в начале жизни C «стандарт» переворачивался как минимум дважды, и некоторые популярные ранние компиляторы заканчивались тем или иным способом, а другие - другим.
Hot Licks
9
@AlokSinghal: Также определяется, определено ли битовое поле типа со знаком intили без знака.
Кит Томпсон
@KeithThompson спасибо за исправление. Я склонен забывать некоторые детали о типах битовых полей, так как я их мало использую.
Алок Сингхал
67

Как указывает Алок , стандарт оставляет это до реализации.

Для gcc значение по умолчанию подписано, но вы можете изменить это с помощью -funsigned-char. примечание: для gcc в Android NDK по умолчанию используется без знака . Вы также можете явно запросить подписанные символы с -fsigned-char.

На MSVC значение по умолчанию подписано, но вы можете изменить его с помощью /J.

R Самуэль Клатчко
источник
2
Интересно, что описание Шильдта не соответствует поведению MSVC, так как его книги обычно ориентированы на пользователей MSVC. Интересно, изменил ли MS по умолчанию в какой-то момент?
Майкл Берр
1
Я думал, что это зависит не от компилятора, а от платформы. Я думал, что char был оставлен как третий тип «символьного типа данных», чтобы соответствовать тому, что системы в то время использовали как печатные символы.
Spidey
10
НКА документы говорят , что машинно-зависимый: « Каждый вид машины имеет значение по умолчанию для того, что символ должен быть Это либо как неподписанный символ по умолчанию или как подписанный полукокс по умолчанию.. »
Deduplicator
1
Можете ли вы предоставить источник для вашей заметки, что на Android по умолчанию является unsigned char?
Phlipsy
1
@Spidey Стандарт C не проводит различий между компиляторами, платформами и архитектурами ЦП. Это просто смешивает их все вместе под «реализацией».
plugwash
35

C99 N1256 черновик 6.2.5 / 15 «Типы» говорит о подписи типа char:

Реализация должна определять символ, чтобы иметь тот же диапазон, представление и поведение, что и подписанный символ или неподписанный символ.

и в сноске:

CHAR_MIN, определенный в <limits.h>, будет иметь одно из значений 0или SCHAR_MIN, и это может быть использовано для различения двух вариантов. Независимо от сделанного выбора, он charявляется отдельным типом от двух других и не совместим ни с одним из них.

Майкл Берр
источник
7

В соответствии с книгой языка программирования C Дениса Ритчи, которая является де-факто стандартной книгой для ANSI C, простые символы, подписанные или неподписанные, зависят от машины, но печатные символы всегда положительны.

Рави Рати
источник
9
Это не обязательно тот случай, когда печатные символы всегда положительны. Стандарт C гарантирует, что все члены базового набора символов выполнения имеют неотрицательные значения.
Кит Томпсон
7

В соответствии со стандартом C подпись простого char - это «определение реализации».

В общем, разработчики выбирали тот, который был бы более эффективен для реализации на их архитектуре. На системах x86 char обычно подписывается. На системах arm это вообще без знака (Apple iOS - исключение).

plugwash
источник
2
@plugwash Ваш ответ, вероятно, был отклонен, потому что Тим Пост потерял свои ключи . Если серьезно, вам не следует беспокоиться об одном понижении, если вы уверены, что ваш ответ правильный (что в данном случае так и есть). Несколько раз со мной случалось, что мои посты были отклонены без уважительной причины. Не беспокойтесь об этом, иногда люди просто делают странные вещи.
Дональд Дак,
1
Почему подписанный char более эффективен на x86? Есть источники?
Мартинкунев
2

Согласно «Языку программирования C ++» Бьярна Страуструпа, char«определяется реализацией». Это может быть signed charили в unsigned charзависимости от реализации. Вы можете проверить, charподписано или нет, используя std::numeric_limits<char>::is_signed.

Boq
источник
9
Это вопрос C. C ++ - это другой язык, и ссылки на C ++ не имеют отношения к C.
ММ
1

Теперь мы знаем, что стандарт оставляет это до реализации.

Но как проверить тип есть signedили unsigned, например char?

Я написал макрос для этого:

#define IS_UNSIGNED(t) ((t)~1 > 0)

и проверить его gcc, clangи cl. Но я не уверен, что это всегда безопасно для других случаев.

南山 竹
источник
Что не так с обычным CHAR_MIN <0 (или WCHAR_MIN <0 для wchar_t)?
Öö Tiib