2013-03-11 107 views
102

爲什麼string::compare返回int而不是像shortchar這樣的較小類型?我的理解是,這種方法只返回-1,0或1.爲什麼string :: compare返回一個int?

第二部分,如果我要設計一個比較方法,比較Foo類型的兩個對象,而我只想返回-1,0或1,會使用short還是char一般是個好主意?

編輯:我已更正,string::compare不返回-1,0或1,它實際上返回值爲0,< 0或0.謝謝讓我排隊。

似乎答案是粗略的,沒有理由返回小於int的類型,因爲返回值是「rvalues」,而那些「rvalues」不會受益於小於int類型(4字節)。另外,許多人指出,無論如何,大多數系統的寄存器大小可能會變大,因爲無論您給它們一個1,2或4個字節的值,這些寄存器都將被填滿,返回沒有真正的優勢一個較小的值。

編輯2:實際上,當使用較小的數據類型(比如對齊,屏蔽等等)時,可能會有額外的處理開銷。一般的共識是,處理大量數據時存在較小的數據類型以節省內存,就像數組的情況一樣。

今天學到了一些東西,再次感謝大家!

+0

我認爲如果有更具體的類型可以用於此目的,會更好。其中只包含Ada95風格的-1,0和1。 – 2013-03-11 12:30:15

+23

「string :: compare()」的文檔明確指出返回值是<0, 0, and > 0 -not- -1,0和1. – 2013-03-11 12:31:52

+6

使用short或char的優點是什麼? 'int'?大多數體系結構都將函數的返回值存儲在一個寄存器中,並且'int'和'short'或'char'一樣可以放入寄存器。對於數字類型使用'char'總是一個壞主意,特別是當你需要保證有符號值被正確處理時。 – 2013-03-11 12:38:39

回答

112

一,規格是,它會返回一個值小於,等於少 到或大於0,不一定是-11。其次,返回值是右值,受到積分 的提升,所以沒有必要返回更小的東西。

在C++中(如在C中),每個表達式都是一個右值或一個左值。從歷史上看,這些術語指左值出現在賦值左側的左值 ,右值只能出現右值 。今天, 非類類型的簡單近似值是左值在內存中有一個地址,而右值不是。因此,你不能採用右值的地址 和cv-qualifiers(條件「訪問」)不適用。在 C++術語中,不具有類類型的右值是純粹的 值,而不是對象。函數的返回值是一個 右值,除非它具有引用類型。 (這 適合在寄存器幾乎總是在寄存器返回非類類型, 例如,而不是在內存中。)

對於類類型的情況下,問題更復雜一點,由於 事實上你可以在右值上調用成員函數。這個 意味着右值必須實際上具有地址,對於指針,並且可以是cv限定的,因爲cv資格 在重載解析中發揮作用。最後,C++ 11引入了 幾個新的區別,以支持右值引用;這些也都主要適用於班級類型。

積分促銷指的是事實,當整型 比int小在表達式中被用作右值,在 大多數情況下,他們將晉升爲int。因此,即使 我有一個聲明爲short a, b;的變量,在表達式a + b中,在添加 發生之前,ab都被提升爲int。同樣,如果我編寫a < 0,則比較結果爲 ,其值爲a,轉換爲int。在實踐中,有很少的情況下,這是有差別的,至少在 2的補充機器整數算術包裝(即 除了極少數的外國人,今天—我認爲唯一的例外是剩餘的大型機) 。不過,即使在 比較常見的機器:

short a = 1; 
std::cout << sizeof(a) << std::endl; 
std::cout << sizeof(a + 0) << std::endl; 

應該給予不同的結果:第一是 sizeof(short),第二sizeof(int)(因爲 積分促銷)的等價物。

這兩個問題是正式正交的; rvalues和lvalues 與整體推廣無關。 ... 積分促銷僅適用於右值,並且大多數(但不是 全部)您將使用右值的情況下將導致 積分促銷。出於這個原因, 確實沒有理由返回小於int的數值。 甚至有一個很好的理由不把它作爲 作爲字符類型返回。重載運算符(如<<)對字符類型的行爲經常表現爲 ,因此您只希望返回 字符作爲字符類型。 (您可能比較 區別:

char f() { return 'a'; } 
std::cout << f() << std::endl;  // displays "a" 
std::cout << f() + 0 << std::endl; // displays "97" on my machine 

不同的是,在第二種情況下,除了擁有 導致出現積分的推廣,這將導致不同的 超載<<被選爲

+46

如果你可以在你的答案中解釋更多關於「返回值是右值,受到整數升級」的情況,那將是很好的。 – 2013-03-11 14:58:12

+0

_「返回值是右值......所以沒有必要返回更小的東西」_喜歡它 – deepmax 2013-03-11 15:01:13

+1

@AlvinWong:請參閱[爲什麼是C字符文字整數而不是字符?]的答案(http://stackoverflow.com/questions/433895/why-are-c-character-literals-ints-instead-of-chars?rq = 1)獲取更多背景信息。 – 2013-03-11 21:30:04

4

如果我設計一個比較兩個Foo類型對象的比較方法,我只想返回-1,0或1,那麼使用short或char通常是個好主意?

這將是好主意。更好的辦法是返回一個布爾值(如果只是想如果相等比較),或枚舉(詳細信息):

enum class MyResult 
{ 
    EQUAL, 
    LESS, 
    GREATER 
}; 

MyResult AreEqual(const Foo &foo1, const Foo & foo2) 
{ 
    // calculate and return result 
} 
+3

「這將是好主意」。你有這個理由嗎? – jrok 2013-03-11 12:30:41

10

這是一個C-主義。

另外,在C需要compare型的功能,他們總是返回int。C++剛剛進行前向(unfortun ately)。

但是,返回int實際上可能是最快的方式,因爲它通常是所用系統寄存器的大小。 (故意模糊。)

+1

實際上'short'和'char'可能會導致性能損失,例如, '255 + 7'對於'char'和'int'具有不同的值,所以正確的實現不一定簡單地存儲'int'可以去的地方,而不用考慮處理它的語義。編譯器不一定會優化這種效率不足的情況。 – 2013-03-11 15:29:39

2

可能使其工作更像strcmp其中也有這set of return values。如果你想要移植代碼,可能會更直觀地讓替代品儘可能接近。

此外,返回值不僅僅是-101<00>0

此外,如上所述,因爲退貨受制於integral promotion,因此將其縮小是沒有意義的。

10

該方法實際上並不返回集合中的整數{ -1, 0, 1 };它實際上可以是的任何積分值。

爲什麼?我能想到的主要原因是int應該是架構的「自然大小」值;對這個大小的值的操作通常至少與對較小或較大值的操作一樣快(並且在許多情況下更快)。所以這是一個允許實現足夠的冗餘來使用最快速的情況。

4

假設有人正在將代碼從C更改爲C++。他們決定將strcmp更換爲string::compare

由於strcmp返回int,它更容易string::compare返回int,作爲禮物。

41

這是有意的,它不返回-1,0或1。

它允許(注意,這不是字符串,但它同樣適用於字符串)

int compare(int *a, int *b) 
{ 
    return *a - *b; 
} 

這是少了很多繁瑣的比:

int compare(int *a, int *b) 
{ 
    if (*a == *b) return 0; 
    if (*a > *b) return 1; 
    return -1; 
} 

這是你必須做什麼[或類似的規定]如果你有返回-1,0或1。

而且它適用於更復雜的類型也:

class Date 
{ 
    int year; 
    int month; 
    int day; 
} 

int compare(const Date &a, const Date &b) 
{ 
    if (a.year != b.year) return a.year - b.year; 
    if (a.month != b.month) return a.month - b.month; 
    return a.day - b.day; 
} 

在字符串的情況下,我們可以這樣做:

int compare(const std::string& a, const std::string& b) 
{ 
    int len = min(a.length(), b.length()); 

    for(int i = 0; i < len; i++) 
    { 
     if (a[i] != b[i]) return a[i] - b[i]; 
    } 
    // We only get here if the string is equal all the way to one of them 
    // ends. If the length isn't equal, "longest" wins. 
    return a.length() - b.length(); 
} 
+1

嘿,這對我的問題很好,太棒了! – 2013-03-11 12:59:59

+8

你的第一個'compare'函數有溢出問題,幸運的是,如果'char *'和'char'小於'int',那麼它們不會同樣適用。例如,如果'* a'是'MAX_INT'並且'* b'是'-1',那麼'* a - * b'是UB,但是如果實現選擇定義它的行爲,那麼結果幾乎肯定是負的。 – 2013-03-11 13:02:39

+0

+1真正從你的例子中學到了一些東西! – 2013-03-11 18:45:15

-1

因爲布爾返回值只能是兩個可能的值(真,假),並且比較函數可以返回三個可能的值(小於,等於,大於)。

更新

雖然的確可以返回一個有符號的短,如果你真的實現自己的比較功能,你可以返回一個半字節或結構有兩個布爾值。

+7

這個問題沒有提到任何有關返回布爾類型的信息。實際上,他特別提出'short'和'char'作爲'int'的替代方案。 – 2013-03-11 12:39:52

25

int是通常是(意思是在大多數現代硬件上)與系統總線和/或cpu寄存器大小相同的整數,即所謂的機器字。因此int通常比較小的類型傳遞得更快,因爲它不需要對齊,屏蔽和其他操作。

較小的類型主要用於允許對陣列和結構進行RAM使用優化。在大多數情況下,它們交換幾個CPU週期(以對齊操作的形式)以獲得更好的RAM使用。

除非你需要強制你的返回值是一箇中等大小的符號或無符號數(char,short ...),你最好用int,這就是標準庫做它的原因。

+0

以合理的方式解釋事物的硬件方面的好方法。 – 2013-03-11 22:13:09

相關問題