Domanda

Il codice seguente viene compilato, ma ha un comportamento diverso per il tipo di carattere rispetto ai tipi di int.

In particolare

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

genera 3 istanze di modelli per tre tipi: int8, uint8 e char. Cosa dà?

Lo stesso non è vero per ints: int e uint32 che generano la stessa istanza del modello e hanno firmato un altro int.

Il motivo sembra essere che C ++ vede char, char con segno e char senza segno come tre tipi diversi. Considerando che int è lo stesso di un int firmato. È giusto o mi sto perdendo qualcosa?

#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;

}

Sto usando g ++ 4.something

È stato utile?

Soluzione

Ecco la tua risposta dallo standard:

  

3.9.1 Tipi fondamentali [basic.fundamental]

     

Gli oggetti dichiarati come caratteri ( char ) devono essere abbastanza grandi da contenere qualsiasi membro del set di caratteri di base dell'implementazione. Se un personaggio di questo set è memorizzato in un oggetto personaggio, il valore integrale di quell'oggetto personaggio è uguale al valore della forma letterale di singolo carattere di quel personaggio. È definito dall'implementazione se un oggetto char può contenere valori negativi. I personaggi possono essere esplicitamente dichiarati unsigned o firmati . carattere , carattere firmato e carattere non firmato sono tre tipi distinti. A char , un char firmato e un char unsigned occupano la stessa quantità di spazio di archiviazione e hanno gli stessi requisiti di allineamento ( basic.types ); cioè, hanno la stessa rappresentazione dell'oggetto. Per i tipi di carattere, tutti i bit della rappresentazione dell'oggetto partecipano alla rappresentazione del valore. Per i tipi di carattere senza segno, tutti i possibili pattern di bit della rappresentazione del valore rappresentano numeri. Questi requisiti non valgono per altri tipi. In ogni particolare   implementazione, un semplice oggetto char può assumere gli stessi valori di un char firmato o di un char unsigned ; quale è definito dall'implementazione.

Altri suggerimenti

Per domande come questa, mi piace guardare nel documento Razionale per C, che spesso fornisce anche risposte a misteri C ++, che a volte sorgono per me quando leggo lo Standard. Ha questo da dire al riguardo:

  

Sono specificati tre tipi di carattere: firmato, semplice e non firmato. Un carattere normale può essere rappresentato come firmato o non firmato, a seconda dell'implementazione, come nella pratica precedente. Il tipo di carattere firmato è stato introdotto per rendere disponibile un tipo intero con segno a un byte su quei sistemi che implementano il carattere normale come non firmato. Per motivi di simmetria, la parola chiave firmata è consentita come parte del nome del tipo di altri tipi integrali.

Razionale per C

Mentre la maggior parte dei tipi integrali come short e int sono predefiniti per essere firmati , char non ha un valore predefinito segnaletica in C ++.

È un errore comune in cui si imbattono i programmatori C ++ quando usano char come tipo intero a 8 bit.

è corretto, carattere , carattere non firmato e carattere firmato sono tipi separati. Probabilmente sarebbe stato bello se char fosse solo un sinonimo di firmato char o unsigned char a seconda dell'implementazione dei compilatori, ma lo standard dice sono tipi separati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top