92

Заинтересовался в связи с одним из ответов на недавний вопрос по C++ (C)

Вычисление длины строки без использования strlen()

Я не встречал, и даже не могу припомнить ни одного описания какой-нибудь системы с размером char больше одного байта. Естественно, речь идет о C (C++), а не о Java и т.п.

Заодно, с байтом не из 8-ми бит кто-нибудь дело имел ?

avp
  • 46,098
  • 6
  • 48
  • 116
  • 7
    По мне, так "sizeof(char) != 1" в С++ это то же самое, что и "true!=true" =)

    Это абсурд....

    – AseN Jun 09 '12 at 21:02
  • 8
    С точки зрения всего багажа Си, такое изменение представить действительно трудно.

    Но, в некоторых (старых) машинах побайтной адресации не было вообще. Символы (для ввода-вывода) упаковывали в машинное слово. Например на БЭСМ (если ничего не путаю) в 48-разрядном слове хранили 8 6-разрядных символов.

    Правда и Си IMHO для них не было. (Сам с такими машинами не встречался, только читал упоминания об этом).

    – avp Jun 09 '12 at 21:17
  • Плюсую, вопрос весьма интересный и глубокий и срывает покровы с причин того, почему миграция к Уникоду сопровождалась такими муками. – karmadro4 Jun 09 '12 at 21:43
  • @avp архитектуры с памятью словами были раньше. Самая прикольная (из того, про что слыхал -- pdp-8 со словом 12 бит. А байт, начиная с S/360 (или чуть раньше) устоялся 8 бит – alexlz Jun 10 '12 at 00:53
  • Не в курсе на счет char, но на практике работал со структурой (int, short, int). Экземпляры такой структуры писались в файл и, соответственно, выравнивались по 4 байтам, то есть short становился int-ом. Мб, и с char-ом такое будет. – RomanoO Jun 10 '12 at 02:48
  • @RomanoO Комментарий хороший, но на sizeof(char) выравнивание все-таки никак не влияет :) – M. Williams Jun 10 '12 at 04:05
  • -2
    Нет гарантии, что в будущих реализациях C тип char сохранит размер в один байт.

    Надо смотреть, насколько критический код лежит ниже проверки.

    –  Oct 26 '12 at 19:51
  • -1
    Все зависит от опций компилятора, если стоит по умолчанию wchar_t то будет 2-а байта, вообще странно видеть такой вопрос, типы данных могут иметь любую длину на разных системах. Если надо - то есть типы данных с заранее заданной длиной в байтах которые не зависят от реализации, в хелпах всё подробно описано. –  Oct 31 '12 at 09:20
  • @AlexandrS, а Вы вопрос-то внимтельно прочитали?

    Сами (в своими ручками писанных программах) sizeof(char) != 1 видели?

    Если да, то опишите систему, компилятор и т.д.

    – avp Oct 31 '12 at 10:21
  • 2
    C++ входящий в поставки от Борланда, сейчас вроде Embarcadero называется, в опциях выставляется тип char чему будет равен –  Oct 31 '12 at 11:50
  • @AlexandrS, интересные сведения о Борланд компайлере.

    Кто и зачем минусовал Ваш ответ - не представляю.

    – avp Oct 31 '12 at 14:41
  • 2
    Я лично минусанул. Пока не увижу сам - не поверю. Скорее всего подразумевалось задание типа _TCHAR, а это ни разу не char. – gecube Nov 01 '12 at 19:52
  • 1
    Какие еще реализации C? – M. Williams Nov 01 '12 at 20:09
  • И еще: http://docwiki.embarcadero.com/RADStudio/XE3/en/Char – gecube Nov 01 '12 at 20:14
  • Вполне возможно. А еще тут недавно появлялся (потом пропал) похожий ответ про Unicode и VS. – avp Nov 01 '12 at 20:18
  • @gecube Радует определение размера char через byte :) – M. Williams Nov 01 '12 at 20:25
  • 1
    @Котик, а до меня кажется дошло и почему определяют размер через байт и про чипы TMS. Мне кажется, что речь идет о минимально адресуемой памяти и про размер этой ячейки в TMS пишут в 8-битных байтах.

    А когда определяют sizeof(char)==1byte, то не уточняют сколько бит в байте.

    – avp Nov 01 '12 at 21:14
  • Согласен, может быть и _TCHAR там был, так что стандарт пока никто не нарушил –  Nov 02 '12 at 04:46
  • ассоциация: http://stackoverflow.com/questions/2215445/ – Nofate Feb 27 '17 at 17:30

6 Answers6

65
  • C++ Standard - 5.3.3 / 1:

    sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1.

  • Более интересным, кстати говоря, является тот факт, что в C sizeof('t') будет равен не 1, а sizeof(int).

    Символьные константы (заключённые в одинарные кавычки) по умолчанию имеют: тип int в С и тип char в C++. Поэтому в C справедливо равенство sizeof('t') == sizeof(int), а в C++ — равенство sizeof('t') == sizeof(char).

M. Williams
  • 23,562
  • 1
    Странно, я рылся в ISO/IEC 9899.1999 и не обнаружил подобного – karmadro4 Jun 09 '12 at 21:37
  • @karmadro4 Собственно, эта штука висит на ru.wikipedia с референсом на Draft C++ and ISO C Compatibility. Не знаю, насколько этому драфту можно доверять, но на практике вроде как действительно так. – M. Williams Jun 09 '12 at 21:43
  • @Котик_хочет_кушать, я думаю, что документ заслуживает доверия. Я собственно полез в спецификацию С причине того, что кресты именно оттуда унаследовали эту неоднозначность. Как ортодоксального паскалиста меня коробит, что они не отделяют символьный тип (char) от очень короткого целого (signed char или unsigned char). – karmadro4 Jun 09 '12 at 21:52
  • 5
    @Котик, спасибо !

    Вот про sizeof('t') == sizeof(int) это может быть важно.

    Даже не задумывался об этом, видимо интуитивно считал, что sizeof('t') == sizeof(char). А оно вот как вышло.

    Особенно же важно различие в этом вопросе между Си и С++ !!!

    Не думал, что мой праздный вопрос принесет такую ценную информацию.

    – avp Jun 09 '12 at 21:57
  • 2
    И Вам @karmadro4, спасибо !

    Сподвигли меня из незаметного комментария ценный вопрос сделать.

    – avp Jun 09 '12 at 22:00
  • Странно, я рылся в ISO/IEC 9899.1999 и не обнаружил подобного

    @karmadro4, если имеется в виду тезис о том, что sizeof(char) = 1, то совершенно правильно не нашли, C (в отличие от C++) не определяет размер объекта типа char.

    – northerner Jun 10 '12 at 10:36
  • 2
    Asen вас минусанул. Похоже "необоснованное затролливание" его заразило. Наверное, он хочет, чтобы у всех ответов количество голосов было, как у него. – devoln Jun 11 '12 at 08:10
  • @GLmonster Не ожидал такого. Я поражен до глубины души и буду жаловаться администрации. – M. Williams Jun 11 '12 at 08:18
  • 1
    @karmadro4

    6.5.3.4 The sizeof operator

    ...

    2 The sizeof operator yields the size (in bytes) of its operand, which may be an

    expression or the parenthesized name of a type.

    ...

    3 When applied to an operand that has type char, unsigned char, or signed char,

    (or a qualified version thereof) the result is 1.

    http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

    – gecube Nov 01 '12 at 20:32
  • @gecube, так это же стандарт
    INTERNATIONAL STANDARD ©ISO/IEC
    
    

    но не все же им следуют? Вот @northerner ведь про реальные чипы

    C2000 and C5000 DSP platforms, a char is 16 bits; on the C3x DSP generation, a char is 32 bits.
    
    

    от TMS писал.

    – avp Nov 01 '12 at 21:01
  • 3
    Нее.... тут другое. Я думаю, что на самом деле для sizeof минимальной единицей является char :-) Т.е. он все меряет в чарах. – gecube Nov 01 '12 at 21:13
  • Очень похоже на правду. – avp Nov 01 '12 at 21:20
  • Да, в общем-то так оно и есть:

    http://processors.wiki.ti.com/index.php/TI_Compilers_and_Industry_Standards

    – gecube Nov 01 '12 at 21:36
  • @gecube sizeof меряет всё же в байтах (исходя из Стандарта). Если для какой-то специфической системы компилятор C++ вернет sizeof(char) != 1, то это лишь говорит о том, что писать переносимый код не получится. А компилятор грубо (в самой базовой части) нарушает Стандарт языка. – αλεχολυτ Nov 14 '15 at 11:56
  • Ым... Равенство sizeof('t') == sizeof(int) в языке С было справедливо во все века и времена. Поэтому откуда вы взяли, что это какая-то новинка "из С99" - не ясно. – AnT stands with Russia Mar 08 '17 at 19:15
54

Системы с размером char больше одного байта не только существовали, но существуют и активно используются в наши дни. Как правило, это встраиваемые системы или специализированные процессоры, например, DSP. Вот цитата из отчета Reading and Writing Binary Files on Targets With More Than 8-Bit Chars компании Texas Instruments, четвертого в мире производителя полупроводниковых приборов:

On theC2000 and C5000 DSP platforms, a char is 16 bits; on the C3x DSP generation, a char is 32 bits.

@avp, прокомментирую

Вот про sizeof('t') == sizeof(int) это может быть важно.

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

#include <stdio.h>

int main() { if (getchar() == EOF) printf("Ох, Щи!!!"); return 0; }

Запустим, передав программке файл с одним символом с кодом 0xFF:

user@linux:~> echo $'\xff' > test
user@linux:~> gcc test.c
user@linux:~> ./a.out < test
user@linux:~>

Никакого вывода, и это логично - getchar() возвращает интовое значение 255, сравниваем с -1 (EOF), не совпадают. Однако следующие два примера

if ('\xff' == EOF)
    printf("Ох, Щи!!!");

и

int c = '\xff';
if (c == EOF)
    printf("Ох, Щи!!!");

демонстрируют равенство значений, поскольку значение 'xff' расширяется до int знаково (получится 0xffffffff = -1). С одной стороны, это источник ошибок, с другой - такое поведение не порождает несовместимости с C++, где char строго равен одному байту и при сравнении с int будет расширен таким же образом.

northerner
  • 4,201
  • 3
    @northerner, спасибо !

    Про TMS не знал, а ведь соседи-коллеги системами TI торгуют.

    Каким образом gethar(), EOF и приведение char к int с расширением знака связаны с sizeof != 1 не понял.

    Самая же типичная (IMHO) ошибка с getchar() и EOF это:

    char c;
    while ((c = getchar()) != EOF) { ...
    
    – avp Jun 10 '12 at 08:48
  • 3
    @avp: sizeof(char) == 1 сколько бы бит в байте не было. 'a' имеет тип int в C. getchar() также int возвращают. Другое дело что машинное определение байта может отличаться от того что думает С компилятор на редких платформах. – jfs Nov 14 '15 at 13:59
  • @avp я считаю, что стоит выбрать другой ответ в качестве принятого, дабы не вводить новых читателей в заблуждение. sizeof(char) по определению равен 1. А то, что байт при этом может содержать не обязательно 8 бит — совсем другая история. – αλεχολυτ Nov 26 '23 at 08:15
  • @αλεχολυτ, согласен. Тем более, похоже, что как сам вопрос, так и ответы на него со временем обрели другой смысл, нежели тот, что озвучен в заголовке (*"видели ли вы когда-нибудь ...") (кстати, можете обратить внимание, я не спрашивал ни o размере sizeof(char), ни о стандартах, ни о наиболее распространенных* компиляторах, ни о том, как сейчас обстоят дела с sizeof-ом .... Т.е. вопрос был об одном, а теперь всеми воспринимается как "сколько весит sizeof(char)?") – avp Nov 26 '23 at 09:13
20

Насколько я знаю:

char - это единственный задокументированный тип с точным указанным размером. Остальные типы имеют относительный размер, например:

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119
5

Может быть выставлено выравнивание по границе int, что сделает верным выражение sizeof(char)==sizeof(int).

Nicolas Chabanovsky
  • 51,426
  • 87
  • 267
  • 507
Dzmitry
  • 59
  • 2
    Постарайтесь писать более развернутые ответы. Поясните, на чем основано ваше утверждение? – Nicolas Chabanovsky May 19 '15 at 05:59
  • Выравнивание для char не может быть больше единицы. Стандарт гарантирует что массив unsigned char адресует все байты без пропусков. Также у char и unsigned char одинаковое неравенство. – Stanislav Volodarskiy Mar 09 '24 at 17:30
5

Столько ответов и только один частично правильный. Нельзя же людей вводить в заблуждение. В стандарте С (6.5.3.4 The sizeof operator)

When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.

и С++ (5.3.3 Sizeof)

sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1.

четко сказано, что тип char имеет размер ОДИН байт. Никакая система не может иметь компилятор, который поддерживает стандарт и который вернет в sizeof(char) что то другое. Иначе это нестандартный компилятор! Теперь о "справедливом" равенстве sizeof(char) == sizeof(int). Не нужно путать значение возвращаемое sizeof с возвращаемым типом, потому что sizeof возвращает тип int и в этом смысле да, равенство может быть. И даже такое равенство может быть 'c' != 0, потому что 'c' будет выровнено до типа int, опять же стандарт. Но, литерал 'c' имеет тип char и поэтому sizeof('c') вернет единицу и, да, типа int. Далее, язык программирования и его реализация на разных платформах это разные вещи. И если квант хранения информации не позволяет хранить один байт, то тогда, да, однобайтовый тип будет храниться в двух и более байтах в зависимости от минимального кванта информации системы. Но это никакого отношения не имеет к sizeof(char). Теперь о дурацком примере, который вводит в еще большее заблуждение.

if (getchar() == EOF)

Естественно, что возвращаемое значение getchar() будет выровнено до int со своим значением, т.е. до 0x000000FF и конечно это не будет равно 0xFFFFFFFF. Следующий более интересный вариант.

if ('\xff' == EOF)

А тут мы сравнивает (char)-1 с (int)-1, почему? Да потому что произошла конвертация из char в int и -1 превратился снова в -1.

UPD: По итогам обсуждения

Стандарт С++ имеет понятие байт и если речь идет об операторе sizeof, то в в этом случае размер возвращается именно в байтах. И хотя в определениях диапазонов и в примерах приводятся значения требующие именно восьми бит, сама битность напрямую в стандарте не определяется. Требуется только то, чтобы байт смог как минимум разместить все зарезервированные в стандарте символы.

Что касается самого определения байта, то оно есть в стандарте IEC 80000 и определяется именно как октет, восемь бит. Любая документация прямо не указывающая размерность байта основывается на стандарте. Но, стандарт не закон, поэтому отклонения могут быть. Например дополнительные биты могут быть использованы для контроля целостности информации или в других служебных целях, но для пользователя все равно будет видны только восемь бит. Любое другое отклонение это скорее анахронизм.

Andrey Sv
  • 1,031
3

Кто-нибудь встречал в своей практике sizeof(char) != 1 ?

Дефайны творят чудеса:

#include <stdio.h>
#define char wchar_t
int main()
{
    printf("sizeof(char)==%d", sizeof(char));
}

Выведет sizeof(char)==2.

devoln
  • 5,441
  • 1
    И где здесь чудеса? Все работает правильно. Если вас это удивляет, то узнайте, как работает препроцессорная директива #define.

    В вашем коде все char`ы заменяются на wchat_t. А размерность WCHAR_T = 2байта....

    – AseN Jun 10 '12 at 15:50
  • 5
    @GLmonster Толсто. – M. Williams Jun 10 '12 at 18:20
  • 1

    И где здесь чудеса? Все работает правильно. Если вас это удивляет

    Я знаю. Меня это абсолютно не удивляет. Я вообще-то сам это написал.

    Толсто.

    А что здесь такого? Вопрос этого не исключает. Вдруг какой-нибудь "программист" захочет таким образом перейти к Юникоду? Так что такое возможно, хоть я на своей практике это и не встречал.

    – devoln Jun 11 '12 at 07:50
  • 1
    @GLmonster Особенно круто будет, если сделать такой global define, а потом удивляться, что все сторонние библиотеки, включая, возможно, и сам рантайм, отваливаются. – M. Williams Jun 11 '12 at 07:58
  • Если пишется кросс-платформенная библиотека, то нужно быть готовым, что например в char будут запихивать юникод (чего бы и нет). Использовании sizeof уменьшает вероятность ошибок полученых в связи с 1) размером типа 2) связанных с выравниванием в структуре или в массиве. – nick_n_a Jun 01 '16 at 15:57