2009-01-12 9 views
35

Der folgende Code wird kompiliert, hat aber für den Zeichenarttyp ein anderes Verhalten als für die int-Typen.char! = (Vorzeichenbehaftetes Zeichen), Zeichen! = (Vorzeichenloses Zeichen)

Insbesondere

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

Ergebnis in 3 instantiations von Vorlagen für drei Typen: int8, uint8 und char. Was gibt?

Das gleiche gilt nicht für ints: int und uint32, die zu derselben Template-Instanziierung führen, und int int.

Der Grund scheint zu sein, dass C++ char, signed char und unsigned char als drei verschiedene Typen sieht. Während int ist das gleiche wie ein vorzeichenbehafteter Int. Ist das richtig oder fehlt mir etwas?

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

} 

Ich bin mit g ++ 4.something

+0

Sie sollten auch beachten, dass es keine Garantie dafür gibt, dass 'int8_t' ein' unterzeichnet char' sein wird und 'uint8_t' wird eine' unsigned char' sein. Insbesondere ist auf Solaris 'int8_t' nur' char' wenn 'char' signiert ist. Mit anderen Worten, Ihr Code wird dort nicht kompiliert. –

+0

"int und uint32, die in der gleichen Vorlage Instanziierung führen, und signed int anderen" Dies sollte definitiv anders herum sein, da int signiert ist. –

Antwort

55

Hier ist die Antwort von der Norm:

3.9.1 Grundtypen [basic.fundamental]

Objekte als Zeichen erklärt (char) soll jedes Mitglied der Umsetzung des speichern groß genug sein, grundlegender Zeichensatz. Wenn ein Zeichen aus dieser Menge in einem Zeichenobjekt gespeichert wird, ist der Integralwert dieses Zeichenobjekts gleich dem Wert der Einzelzeichen-Literalform dieses Zeichens. Es ist implementierungsdefiniert, ob ein char Objekt negative Werte enthalten kann. Zeichen können explizit unsigned oder signed deklariert werden. Plain char, signed char und unsigned char sind drei verschiedene Typen. Eine char, eine signed char und eine unsigned char besetzen die gleiche Menge an Speicher und haben die gleichen Ausrichtungsanforderungen (basic.types); das heißt, sie haben die gleiche Objektdarstellung. Bei Zeichentypen sind alle Bits der Objektdarstellung an der Wertdarstellung beteiligt. Für vorzeichenlose Zeichentypen stellen alle möglichen Bitmuster der Wertdarstellung Zahlen dar. Diese Anforderungen gelten nicht für andere Typen. In einer bestimmten Implementierung kann ein einfaches char Objekt entweder dieselben Werte annehmen wie ein signed char oder ein unsigned char; welches ist implementierungsdefiniert.

13

die richtige ist, char, unsigned char und signed char sind getrennte Arten. Es wäre wahrscheinlich nett gewesen, wenn char war nur ein Synonym für entweder signed char oder unsigned char abhängig von Ihrer Compiler-Implementierung, aber der Standard sagt, sie sind separate Typen.

16

Während die meisten integralen Typen wie short und int Standard signed zu sein, char keinen Standard Beschilderung in C++ haben.

Es ist ein häufiger Fehler, mit dem C++ - Programmierer arbeiten, wenn sie char als 8-Bit-Integer-Typ verwenden.

+2

+1 für den Vergleich zu kurz und int auch. – imallett

+0

+1, weil Sie die Unterschiede in den Datentypen sehr kurz erklären und implizieren, wie sie im Vergleich verwendet werden sollten. – Peri461

20

Für Fragen wie diese schaue ich gerne in das Rational-Dokument für C, das oft auch Antworten auf C++ - Rätsel liefert, die mir beim Lesen des Standards manchmal auffallen. Es hat Folgendes zu sagen:

Drei Typen von Zeichen angegeben: signiert, plain und unsigned. Ein einfaches Zeichen kann abhängig von der Implementierung, wie in der früheren Praxis, entweder als vorzeichenbehaftet oder als vorzeichenlos dargestellt werden. Der Typ signed char wurde eingeführt, um einen signierten Integer-Typ mit einem Byte auf solchen Systemen zur Verfügung zu stellen, die einfaches Zeichen als unsigned implementieren. Aus Gründen der Symmetrie ist das Schlüsselwort signed als Teil des Typnamens anderer ganzzahliger Typen zulässig.

Rationale for C

+0

Also, warum brauchen wir 'signed char'? Nur um damit eine 1-Byte-Ganzzahl mit Vorzeichen darzustellen? – Alcott

+1

@Alcott Ich denke, 'char' könnte signiert sein, oder könnte unsigniert sein, das ist die Implementierung definiert, aber' signed char' ist immer signiert, und 'unsigned char' ist immer vorzeichenlos, wenn Sie sicher/explizit sein wollen Art – hanshenrik