Char! = (символ со знаком), char! = (символ без знака)

Приведенный ниже код компилируется, но его поведение для типа char отличается от поведения для типов int.

В частности

   cout << getIsTrue< isX<int8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<uint8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<char>::ikIsX  >() << endl;

в результате получается 3 экземпляра шаблонов для трех типов: int8, uint8 и char. Что дает?

То же самое не относится к ints: int и uint32, которые приводят к одному и тому же экземпляру шаблона, а подписанный int - к другому.

Причина, по-видимому, в том, что C++ видит char, signed char и unsigned char как три разных типа. В то время как int - это то же самое, что и подписанное int. Это правильно или я что-то упускаю?

#include <iostream>

using namespace std;

typedef   signed char       int8;
typedef unsigned char      uint8;
typedef   signed short      int16;
typedef unsigned short     uint16;
typedef   signed int        int32;
typedef unsigned int       uint32;
typedef   signed long long  int64;
typedef unsigned long long uint64;

struct TrueType {};
struct FalseType {};

template <typename T>
struct isX
{
   typedef typename T::ikIsX ikIsX;
};


// This  int==int32 is ambiguous
//template <>            struct isX<int  >    { typedef FalseType ikIsX; };  // Fails
template <>            struct isX<int32  >  { typedef FalseType ikIsX; };
template <>            struct isX<uint32 >  { typedef FalseType ikIsX; };


// Whay isn't this ambiguous? char==int8
template <>            struct isX<char  >  { typedef FalseType ikIsX; };
template <>            struct isX<int8  >  { typedef FalseType ikIsX; };
template <>            struct isX<uint8 >  { typedef FalseType ikIsX; };


template <typename T> bool getIsTrue();
template <>           bool getIsTrue<TrueType>() { return true; }
template <>           bool getIsTrue<FalseType>() { return false; }

int main(int, char **t )
{
   cout << sizeof(int8) << endl;  // 1
   cout << sizeof(uint8) << endl; // 1
   cout << sizeof(char) << endl;  // 1

   cout << getIsTrue< isX<int8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<uint8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<char>::ikIsX  >() << endl;

   cout << getIsTrue< isX<int32>::ikIsX  >() << endl;
   cout << getIsTrue< isX<uint32>::ikIsX  >() << endl;
   cout << getIsTrue< isX<int>::ikIsX  >() << endl;

}

Я использую g ++ 4. что-то

Вы также должны отметить, что нет никакой гарантии, что int8_t будет signed char, а uint8_t будет unsigned char. В частности, в Solaris int8_t - это просто char, если char подписан. Другими словами, ваш код там не скомпилируется.

Michał Górny 11.10.2016 18:05

"int и uint32, которые приводят к тому же экземпляру шаблона, а подписанный int другой", это определенно должно быть наоборот, поскольку int подписан.

Felix Dombek 07.03.2018 16:24
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
44
2
18 450
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

это правильно, char, unsigned char и signed char - это разные типы. Вероятно, было бы неплохо, если бы char был просто синонимом signed char или unsigned char, в зависимости от реализации вашего компилятора, но в стандарте говорится, что это разные типы.

Ответ принят как подходящий

Вот ваш ответ из стандарта:

3.9.1 Fundamental types [basic.fundamental]

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. A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (basic.types); that is, they have the same object representation. For character types, all bits of the object representation participate in the value representation. For unsigned character types, all possible bit patterns of the value representation represent numbers. 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.

В то время как большинство интегральных типов, таких как short и int, по умолчанию являются signed, char не имеет обозначений по умолчанию в C++.

Это не тип signed char и не unsigned char, поэтому реализации могут решить, подписан ли он.

Это распространенная ошибка, с которой сталкиваются программисты на C++, когда используют char как 8-битный целочисленный тип.

+1, потому что вы очень кратко объясняете различия в типах данных и подразумеваете, как их следует использовать в сравнении.

Joshua Detwiler 23.06.2017 16:31

Историческая сноска: я слышал, что это произошло потому, что ранние версии C не указывали подписи char, поэтому разные компиляторы делали разные вещи, а затем стандарт сохранил это поведение, чтобы старый код продолжал работать с теми же компиляторами.

Mooing Duck 29.09.2020 21:31

По таким вопросам, как этот, мне нравится заглядывать в документ Rationale для C, который также часто дает ответы на загадки C++, которые иногда возникают у меня при чтении Стандарта. Об этом говорится следующее:

Three types of char are specified: signed, plain, and unsigned. A plain char may be represented as either signed or unsigned, depending upon the implementation, as in prior practice. The type signed char was introduced to make available a one-byte signed integer type on those systems which implement plain char as unsigned. For reasons of symmetry, the keyword signed is allowed as part of the type name of other integral types.

Обоснование C

Итак, зачем нам signed char? Просто для того, чтобы использовать его для представления однобайтового целого числа со знаком?

Alcott 16.08.2012 05:46

@Alcott я думаю, что char может быть подписан или может быть без знака, что определяется реализацией, но signed char всегда подписан, а unsigned char всегда без знака, если вы хотите быть уверенным / явным в типе

hanshenrik 08.08.2017 19:15

Другие вопросы по теме