2009-01-12 142 views
35

下面的代碼會編譯,但對於char類型而言,其行爲與int類型不同。char!=(signed char),char!=(unsigned char)

特別

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

結果在模板3個實例爲三種類型:INT8,UINT8和炭。是什麼賦予了?

對於ints:int和uint32也是如此,它們導致相同的模板實例化,並對另一個int進行了簽名。

原因似乎是C++將char,signed char和unsigned char看作三種不同的類型。而int與signed 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.something

+0

你還應該注意,不能保證`int8_t`將是一個`簽署char`和`uint8_t`將是一個'無符號char`。特別是在Solaris上,如果`char`被簽名,`int8_t`就是`char`。換句話說,你的代碼將無法在那裏編譯。 – 2016-10-11 15:05:57

+0

「int和uint32導致相同的模板實例化,並且對另一個int進行了signed int」這應該肯定是int的簽名方式。 – 2018-03-07 13:24:50

回答

55

下面是標準答案:

3.9.1基本類型[basic.fundamental]聲明爲字符(char

對象應足夠大來存儲執行的任何成員基本字符集。如果該組中的字符存儲在字符對象中,則該字符對象的整數值等於該字符的單個字符字面值形式的值。它是實現定義對象是否可以保存負值。字符可以明確聲明爲unsignedsigned平原char,signed charunsigned char是三種不同的類型。 A charsigned charunsigned char佔用相同的存儲量並具有相同的對齊要求(basic.types);也就是說,它們具有相同的對象表示。對於字符類型,對象表示的所有位都參與值表示。對於無符號字符類型,值表示的所有可能位模式都表示數字。這些要求不適用於其他類型。在任何特定的 實現中,普通對象可以採取與signed charunsigned char相同的值;哪一個是實現定義的。

13

這是正確的,charunsigned charsigned char是不同的類型。如果char只是signed charunsigned char的同義詞,這可能會很好,具體取決於您的編譯器實現,但標準說它們是不同的類型。

16

雖然大部分組成類型,如shortint被默認爲signedchar沒有在C默認標牌++。

C++程序員在使用char作爲8位整數類型時遇到了一個常見的錯誤。

+2

+1用於比較short和int以及。 – imallett 2013-06-25 08:04:47

20

對於這樣的問題,我喜歡查看C的基本原理文檔,該文檔通常也提供了對C++奧祕的答案,有時在閱讀標準時會出現。它有這樣的說法:

指定了三種類型的char:signed,plain和unsigned。一個普通的字符可以表示爲有符號或無符號,這取決於實現,如以前的做法。引入類型signed char是爲了在實現plain char爲unsigned的系統上提供一個字節的帶符號整數類型。出於對稱的原因,關鍵字signed被允許作爲其他整型的類型名稱的一部分。

Rationale for C