char, signed char, unsigned char
От: nen777w  
Дата: 16.02.17 22:00
Оценка:
Почему с точки зрения компилятора это 3 разных типа?
В стандарте ничего внятного по этому поводу нет (ну или я не смог найти) и почему это касается только (s/u) char (в чем так сказать причина)?
То что это 3 разных типа говорит нам:
std::cout << std::is_same<signed char, char>::value << std::endl; << false
std::cout << std::is_same<unsigned char, char>::value << std::endl; << false


Более того, будет сгенрировано 2 одинаковых копии метода A<char / signed char>::foo() https://godbolt.org/g/GhGMJS
Отредактировано 16.02.2017 22:01 nen777w . Предыдущая версия .
Re: char, signed char, unsigned char
От: Muxa  
Дата: 16.02.17 22:49
Оценка:
N>Почему с точки зрения компилятора это 3 разных типа?
N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти) и почему это касается только (s/u) char (в чем так сказать причина)?
N>Более того, будет сгенрировано 2 одинаковых копии метода A<char / signed char>::foo() https://godbolt.org/g/GhGMJS

Если выбрать другой компилятор, то одинаковыми окажется другая пара char / unsigned char
https://godbolt.org/g/vGhiY7c

Видимо чем считать обычный char (signed или unsigned) отдано под ответственность компилятора.
Отредактировано 16.02.2017 22:50 Muxa . Предыдущая версия .
Re: char, signed char, unsigned char
От: Pzz Россия https://github.com/alexpevzner
Дата: 17.02.17 00:00
Оценка: +1
Здравствуйте, nen777w, Вы писали:

N>Почему с точки зрения компилятора это 3 разных типа?


Чтобы жизнь мёдом не казалась.

В C/C++ очень неудачная система типов. В C это не слишком чувствуется, потому что там в типы вкладывается не так много смысла, а вот в C++ это большая проблема.

N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти) и почему это касается только (s/u) char (в чем так сказать причина)?


Когда 100500 лет назад придумали C, была идея, что на некоторых машинах, в зависимости от их системы команд, будет удобнее, если char будет знаковым, а на некоторых — наоборот. Поэтому язык не определяет знаковость char'а, если она не указана явно. А про int такой идеи не было
Re: char, signed char, unsigned char
От: rg45 СССР  
Дата: 17.02.17 08:52
Оценка: +2
Здравствуйте, nen777w, Вы писали:

N>Почему с точки зрения компилятора это 3 разных типа?

N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти) и почему это касается только (s/u) char (в чем так сказать причина)?

3.9.1 Fundamental types
1 Objects declared as characters (char) shall be large enough to store any member of the implementation’s basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation defined whether a char object can hold negative values. Characters can be explicitly declared unsigned or signed. Plain char, signed char, and unsigned char are three distinct types, collectively called narrow character types. A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (3.11); that is, they have the same object representation. For narrow character types, all bits of the object representation participate in the value representation. For unsigned narrow character types, each possible bit pattern of the value representation represents a distinct number. These requirements do not hold for other types. In any particular implementation, a plain char object can take on either the same values as a signed char or an unsigned char; which one is implementation-defined. For each value i of type unsigned char in the range 0 to 255 inclusive, there exists a value j of type char such that the result of an integral conversion (4.7) from i to char is j, and the result of an integral conversion from j to unsigned char is i.

--
Не можешь достичь желаемого — пожелай достигнутого.
Re: char, signed char, unsigned char
От: MasterZiv СССР  
Дата: 17.02.17 09:28
Оценка: :)
Здравствуйте, nen777w, Вы писали:

N>Почему с точки зрения компилятора это 3 разных типа?


Потому что с точки зрения стандарта это 3 разных типа. Точнее, 2 разных типа -- signed char, unsigned char и char является синонимом к одному из двух предыдущих.

N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти)


Да ладно... Я искать конечно не буду, но там это 100% есть.

N>почему это касается только (s/u) char (в чем так сказать причина)?


Нет, это касается всех типов, которые имеют варианты signed/unsigned.
Например, int также имеет 2 типа , и int является синонимом signed int.

P.S. блин, таки наврал...
Отредактировано 17.02.2017 9:30 MasterZiv . Предыдущая версия .
Re: char, signed char, unsigned char
От: Erop Россия  
Дата: 17.02.17 09:53
Оценка: 4 (1) +1
Здравствуйте, nen777w, Вы писали:

N>Почему с точки зрения компилятора это 3 разных типа?

Наследие С. Общего у этих типов -- одинаковое число бит и способ их (бит) хранения в памяти, что позволяет их всех троих reinterpret_cast'ить друг к другу.

Отличие в целях.

char -- буквы
signed char -- маленькие целые со знаком
unsigned char -- маленькие натуральные с нулём.

Смысл в том, что возможны и даже были реализации, где char был МЕНЬШЕ минимального адресуемого аппаратурой слова. Например 48-битная машина, ориентированная на выч.маты
И если мы работаем с байтами, как с буквами, то много чего можно соптимизировать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: char, signed char, unsigned char
От: alzt  
Дата: 17.02.17 10:28
Оценка: +1
Здравствуйте, Muxa, Вы писали:

M>Если выбрать другой компилятор, то одинаковыми окажется другая пара char / unsigned char

M>https://godbolt.org/g/vGhiY7c

Ещё и опции есть. Например -funsigned-char у gcc.
Re[2]: char, signed char, unsigned char
От: rg45 СССР  
Дата: 17.02.17 10:37
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, nen777w, Вы писали:


N>>Почему с точки зрения компилятора это 3 разных типа?

E>Наследие С. Общего у этих типов -- одинаковое число бит и способ их (бит) хранения в памяти, что позволяет их всех троих reinterpret_cast'ить друг к другу.

Вот как раз C, в отличие от C++, не требует чтобы char был отдельным типом:

5.2.4.2.1/2
If the value of an object of type char is treated as a signed integer when used in an expression, the value of CHAR_MIN shall be the same as that of SCHAR_MIN and the value of CHAR_MAX shall be the same as that of SCHAR_MAX. Otherwise, the value of CHAR_MIN shall be 0 and the value of CHAR_MAX shall be the same as that of UCHAR_MAX.

--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: char, signed char, unsigned char
От: Erop Россия  
Дата: 17.02.17 10:40
Оценка:
Здравствуйте, rg45, Вы писали:

R>Вот как раз C, в отличие от C++, не требует чтобы char был отдельным типом:


В С с типизацией вообще не строго всё. Там этот вопрос скорее теологический же.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: char, signed char, unsigned char
От: uzhas Ниоткуда  
Дата: 17.02.17 11:14
Оценка: +1
Здравствуйте, nen777w, Вы писали:

N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти)


как раз этот момент в стандарте довольно четко описан
Re[2]: char, signed char, unsigned char
От: Erop Россия  
Дата: 17.02.17 12:35
Оценка: +1 :)
Здравствуйте, uzhas, Вы писали:

N>>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти)


U>как раз этот момент в стандарте довольно четко описан


Зависит от языка...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: char, signed char, unsigned char
От: Ops Россия  
Дата: 18.02.17 10:08
Оценка:
Здравствуйте, Erop, Вы писали:

E>Зависит от языка...


Код из стартового сообщения ни на что не намекает?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[4]: char, signed char, unsigned char
От: Erop Россия  
Дата: 18.02.17 22:32
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>Код из стартового сообщения ни на что не намекает?

Намекает, что ТС проверял в С++...
Это никак не меняет того, что в С и С++ это дело освещено по разному...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: char, signed char, unsigned char
От: tstalker Украина  
Дата: 21.02.17 12:56
Оценка: -1
Здравствуйте, nen777w, Вы писали:

N>Почему с точки зрения компилятора это 3 разных типа?

N>В стандарте ничего внятного по этому поводу нет (ну или я не смог найти) и почему это касается только (s/u) char (в чем так сказать причина)?
N>То что это 3 разных типа говорит нам:
N>
N>std::cout << std::is_same<signed char, char>::value << std::endl; << false
N>std::cout << std::is_same<unsigned char, char>::value << std::endl; << false
N>


N>Более того, будет сгенрировано 2 одинаковых копии метода A<char / signed char>::foo() https://godbolt.org/g/GhGMJS


Существуют архитектуры, где char по умолчанию signed char. Пример: x86-64.
Существуют архитектуры, где char по умолчанию unsigned char. Пример: Allwinner A1X.
Соответственно, знаковость char не закреплена жёстко в стандарте, а находится в зависимости от архитектуры.
Впрочем, это не объясняет, почему всё-таки 3 разных типа.
Камрад rg45 выше привёл цитату из стандарта, почему так.
Да, согласен — это противоречит элементарной логике и здравому смыслу.
Увы — этот мир несовершенен...
Re[3]: char, signed char, unsigned char
От: N. I.  
Дата: 21.02.17 16:44
Оценка: 8 (1)
rg45:

R>Вот как раз C, в отличие от C++, не требует чтобы char был отдельным типом:


Всё ж-таки требует, но через одно место:

The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char. [Footnote: CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be used to distinguish the two options. Irrespective of the choice made, char is a separate type from the other two and is not compatible with either.]


Размещение такого уточнения в сноске похоже на нарушение регламента составления стандартов (если только из нормативной части не следует, что данные типы — непременно разные), но это обстоятельство вряд ли заставит кого-то трактовать стандарт C иначе.

Как следствие, вот такие варианты

ptrdiff_t char_ptr_diff(char *p1, signed char *p2)
{
    return p1 - p2;
}

ptrdiff_t char_ptr_diff(char *p1, unsigned char *p2)
{
    return p1 - p2;
}

по-любому являются ошибочными и для обоих требуется выдача компилятором какого-нибудь diagnostic message из-за нарушения constraints.
Отредактировано 21.02.2017 19:21 N. I. . Предыдущая версия .
Re[2]: char, signed char, unsigned char
От: Pzz Россия https://github.com/alexpevzner
Дата: 22.02.17 18:13
Оценка:
Здравствуйте, Erop, Вы писали:

E>char -- буквы


Как-то буквы плохо сочетаются со знаковостью...

E>signed char -- маленькие целые со знаком

E>unsigned char -- маленькие натуральные с нулём.

При всем при том, по определению sizeof(char) == sizeof(signed char) == sizeof(unsigned char) == 1. Т.е., трудно будет сделать компилятор, который char'ы будет хранить с байтах (пусть и не адресуемых), а signed/unsigned char'ы в чем-то другом, более удобном для аппаратуры.

E>Смысл в том, что возможны и даже были реализации, где char был МЕНЬШЕ минимального адресуемого аппаратурой слова. Например 48-битная машина, ориентированная на выч.маты


Интересно, как в этих реализациях работала адресная арифметика на указателях на char...

E>И если мы работаем с байтами, как с буквами, то много чего можно соптимизировать...


Да, но к сожалению в Си можно поработать с char'ом, как с буквой, а потом с тем же самым char'ом, как не с буквой. И как компилятор с этим разберется?
Re[3]: char, signed char, unsigned char
От: Erop Россия  
Дата: 22.02.17 18:32
Оценка:
Здравствуйте, Pzz, Вы писали:

E>>char -- буквы


Pzz>Как-то буквы плохо сочетаются со знаковостью...

Это я не понял, буквы -- это буквы. А коды букв — это коды. Коды можно выбрать такие, как удобно для реализации. Например +1 будет буква "а", а -1 — буква "А"
Это в стандартах обоих языков вообще никак не регламентируется, вроде, за исключением того, что латинский алфавит в одном регистре должен подряд идти, и цифры тоже, и то я не уверен, что такое требование есть в актуальном стандарте.


E>>signed char -- маленькие целые со знаком

E>>unsigned char -- маленькие натуральные с нулём.

Pzz>При всем при том, по определению sizeof(char) == sizeof(signed char) == sizeof(unsigned char) == 1. Т.е., трудно будет сделать компилятор, который char'ы будет хранить с байтах (пусть и не адресуемых), а signed/unsigned char'ы в чем-то другом, более удобном для аппаратуры.


Это СМЫСЛ этих типов. Это ОДНИ И ТЕ ЖЕ БИТЫ. Просто их интерпретация может быть такой и другой. Но БИТЫ ТЕ ЖЕ.
В этом смысле char -- это то, как на данной платформе удобно работать с буквами, грубо говоря. А signed|unsigned char — это работа с теми же БИТАМИ, как с маленькими числами.

Pzz>Интересно, как в этих реализациях работала адресная арифметика на указателях на char...

В чём проблема? указатель на char был указателем на слово + смещение

Pzz>Да, но к сожалению в Си можно поработать с char'ом, как с буквой, а потом с тем же самым char'ом, как не с буквой. И как компилятор с этим разберется?


Провалится оптимизация (не состоится)
Но, например, зато, char'ы можно собирать в удобные строковые литералы, и они ДОЛЖНЫ уметь это делать эффективно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: char, signed char, unsigned char
От: Pzz Россия https://github.com/alexpevzner
Дата: 22.02.17 18:50
Оценка:
Здравствуйте, Erop, Вы писали:

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


Не годидзе.

Согласно стандарту, функции типа getchar() возвращают символы, как unsigned char, скастированный в int. Соответственно, если какие-то буквы имеют отрицательные коды, получится нехорошо.

Pzz>>При всем при том, по определению sizeof(char) == sizeof(signed char) == sizeof(unsigned char) == 1. Т.е., трудно будет сделать компилятор, который char'ы будет хранить с байтах (пусть и не адресуемых), а signed/unsigned char'ы в чем-то другом, более удобном для аппаратуры.


E>Это СМЫСЛ этих типов. Это ОДНИ И ТЕ ЖЕ БИТЫ. Просто их интерпретация может быть такой и другой. Но БИТЫ ТЕ ЖЕ.

E>В этом смысле char -- это то, как на данной платформе удобно работать с буквами, грубо говоря. А signed|unsigned char — это работа с теми же БИТАМИ, как с маленькими числами.

Char — это либо signed char, либо unsigned char, на усмотрение компилятора (хотя формально это разные типы, т.е., нельзя, к примеру, вычесть из unsigned char* из char*).

Я не могу себе, однако, представить аппаратуру, которой было бы удобнее работать со знаковыми char'ами. Поэтому я не понимаю, каким местом думали граждане-создатели C, не зафиксировав в стандарте char, как синоним к unsigned char.

Pzz>>Интересно, как в этих реализациях работала адресная арифметика на указателях на char...

E>В чём проблема? указатель на char был указателем на слово + смещение

Очень неэффективно.

Pzz>>Да, но к сожалению в Си можно поработать с char'ом, как с буквой, а потом с тем же самым char'ом, как не с буквой. И как компилятор с этим разберется?


E>Провалится оптимизация (не состоится)


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

E>Но, например, зато, char'ы можно собирать в удобные строковые литералы, и они ДОЛЖНЫ уметь это делать эффективно...


В каком смысле, делать эффективно. Вся работа со строковыми литералами происходит в голове у компилятора. Потом они становятся просто массивами байтов.
Re[5]: char, signed char, unsigned char
От: Erop Россия  
Дата: 22.02.17 18:57
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Не годидзе.


Pzz>Согласно стандарту, функции типа getchar() возвращают символы, как unsigned char, скастированный в int. Соответственно, если какие-то буквы имеют отрицательные коды, получится нехорошо.


Ну, тем не менее, как-то работает прямо сейчас, когда много где char знаковый...
Главное по дури 'я' за конец файла не принять


Pzz>Char — это либо signed char, либо unsigned char, на усмотрение компилятора (хотя формально это разные типы, т.е., нельзя, к примеру, вычесть из unsigned char* из char*).


В С можно. В плюсах нельзя.
Я пока не пойму, что ты хочешь сказать. Я даже не понимаю, ты пытаешься оспорить или уточнить

Pzz>Я не могу себе, однако, представить аппаратуру, которой было бы удобнее работать со знаковыми char'ами. Поэтому я не понимаю, каким местом думали граждане-создатели C, не зафиксировав в стандарте char, как синоним к unsigned char.


Ну, например, долгое время было популярно в старшем бите хранить вовсе и не знак, а контрольную сумму, это если буква с фотосчитывателя пришла, например...

Pzz>>>Интересно, как в этих реализациях работала адресная арифметика на указателях на char...

E>>В чём проблема? указатель на char был указателем на слово + смещение

Pzz>Очень неэффективно.

Тратить по 6 байт на одну букву -- ещё менее эффективно же

E>>Но, например, зато, char'ы можно собирать в удобные строковые литералы, и они ДОЛЖНЫ уметь это делать эффективно...


Pzz>В каком смысле, делать эффективно. Вся работа со строковыми литералами происходит в голове у компилятора. Потом они становятся просто массивами байтов.


Это если аппаратура так умеет. А если нет?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: char, signed char, unsigned char
От: Pzz Россия https://github.com/alexpevzner
Дата: 22.02.17 19:06
Оценка:
Здравствуйте, Erop, Вы писали:

E>В С можно. В плюсах нельзя.

E>Я пока не пойму, что ты хочешь сказать. Я даже не понимаю, ты пытаешься оспорить или уточнить

Я не понимаю, зачем создатели Си оставили свободу разработчикам компилятора, делать char знаковым или нет. Впрочем, вряд ли мы узнаем ответ на этот вопрос.

Но вот в языке Go, созданным примерно теми же людми, такого балагана уже нет.

Pzz>>Очень неэффективно.

E>Тратить по 6 байт на одну букву -- ещё менее эффективно же

Я слышал, что был компилятор Си для БЭСМ-6. Но мне удивительно, неужели кем-то он всерьез использовался? Все же, Си, как бы это не было кокетливо обойдено в спецификации языка, неявно предполагает, что отдельные байты в машине адресуемы, и что адресная арифметика — штука такая же быстрая, как арифметика целых чисел сравнимой разрядности...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.