vak: (Default)
[personal profile] vak
Копаясь в семантике компилятора, чего только не узнаешь. Выясняется, в языке Си не два типа "signed char" и "unsigned char", а три. Тип просто "char" отличается от первых двух, хоть и ведет себя как один из них. Обнаружить этот факт можно, попытавшись повторно определить typedef:
$ cat foo.c
typedef char foo;
typedef signed char foo;

$ cc -c foo.c
typedef-char.c:2:21: error: typedef redefinition with different types ('signed char' vs 'char')
2 | typedef signed char foo;
| ^
typedef-char.c:1:14: note: previous definition is here
1 | typedef char foo;
| ^
1 error generated.
С другими типами такого выпендрёжа нет. Компилируется без ошибок:
$ cat bar.c
typedef int bar;
typedef signed int bar;

$ cc -c bar.c

Date: 2025-06-06 05:29 (UTC)
archaicos: Шарж (Default)
From: [personal profile] archaicos
Там ещё и три типа int: signed int, unsigned int и просто int!
Если битовое поле определено через просто int, то оно может быть signed int или unsigned int.

Date: 2025-06-06 06:43 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
На Си можно писать 20 лет и не знать этой тонкости, потому что в здравом уме никто не будет писать функции вида:
foo(unsigned char)

А в учебниках Си++ я встречал упоминание о трёх типах char в главах о перегрузке функций для разных типов.

Date: 2025-06-06 07:41 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
В `unsigned char` преобразуют уже внутри функций если надо

Си вольно кастит типы
Для вызывающей стороны одинаковы все 3 варианта:
foo(unsigned char)
foo(char)
foo(signed char)

А так как можно определить только одну функцию с данным именем, пишут как проще, т.е. `char`,
Edited Date: 2025-06-06 07:42 (UTC)

Date: 2025-06-06 08:13 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Понятно что warnings и предназначены отлавливать опасные места Си.
Проверил в GCC и VC c опцией -Wall, код скомпилился без Warning


На практике же, если работать с байтами, используют `uint8_t`, и каким typedef он определен - вопрос реализации.

Если работают с текстом, `signed char`, `unsigned char` только ухудшают читаемость

А `putbyte(255);` - это пример как не надо делать, смешивать типы.






Edited Date: 2025-06-06 08:14 (UTC)

Date: 2025-06-06 08:38 (UTC)
From: [personal profile] chabapok
Кстати вот, вспоминается, что там оно еще и компилит эти типы по отдельным правилам. По стандарту указателями на char, unsigned char, signed char разрешено менять байтики под другими типами.

вот тут сравнение: https://gcc.godbolt.org/z/zrcvrdxTh

То есть чары (все 3 варианта) ведут себя чуть более злобно в некоторых ситуациях, и компилятор исходит из предположения, что в приведенном примере data и result это может быть одна и та же область памяти. Из за этого приходится делать дополнительный финт ушами. Сам пример с++ный, но по идее в си компилятор должен себя вести так же.

Это предположение можно отключить написав "char * __restrict data", но сишно ли слово __restrict, и только сиплюсплюсно - я не знаю.

В с++20 завели менее злобный char8_t, который означает, что указатели совершенно точно указывают на разные места. История про char8_t уже не про си.

Date: 2025-06-06 10:53 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
Задача для интервью - что-нибудь забацать с chars, а они будут signed, и получится фигня при исполнении.

Date: 2025-06-06 15:04 (UTC)
From: [personal profile] caztd
Интересно, а указатели на них (char* vs signed char*) -- тоже разные типы?
Лениво проверять.
То есть это так в спецификации определено а не просто bug/feature компилятора?

Date: 2025-06-06 15:15 (UTC)
From: [personal profile] dedekha
С - очень старый язык и ломать backward совместимость никто не хочет.

"Я вам больше скажу": 30 лет жду нормальных классов для чисел в С++, скорее всего так и умру не дождавшись.

Date: 2025-06-06 20:02 (UTC)

Date: 2025-06-06 20:22 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Не всегда так

в MSVC есть встроеный тип __int8


Думаю, signed/unsigned появились из-за неопределенности в начальном стандарте (K&R) насчет `char`
Часть реализаций делала знаковым, часть наоборот
Потом появились опции компиляторов, позволяющие задать.
И стандартизировать знаковость `char` было уже поздно.



Edited Date: 2025-06-06 20:54 (UTC)

Date: 2025-06-06 21:08 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
Ох я в курсе... помню ещё этот ужас.