[英]The ternary (conditional) operator in C
條件運算符需要什么? 在功能上它是多余的,因為它實現了一個 if-else 結構。 如果條件運算符比等效的 if-else 賦值更有效,為什么編譯器不能更有效地解釋 if-else?
在C語言中,它的真正用途是它是一個表達式而不是一條語句。 也就是說,您可以將其放在語句的右側(RHS)。 因此,您可以更簡潔地編寫某些內容。
給出的其他一些答案很好。 但是令我驚訝的是,沒有人提到它可以用來以緊湊的方式幫助實現const
正確性。
像這樣:
const int n = (x != 0) ? 10 : 20;
因此基本上n
是一個const
其初始值取決於條件語句。 最簡單的辦法是使n
不是一個const
,這將允許一個普通的if
將其初始化。 但是,如果您希望將其設為const
,則無法使用常規if
來完成。 您可以做的最好的替代方法是使用如下的輔助函數:
int f(int x) {
if(x != 0) { return 10; } else { return 20; }
}
const int n = f(x);
但是三元if版本要緊湊得多,而且可讀性更高。
三元運算符是語法和可讀性的便利,而不是性能捷徑。 人們因其復雜性各不相同的條件而在優點上有所分歧,但對於較短的條件,使用單行表達式可能會很有用。
而且,由於它是一個表達式,如查理·馬丁(Charlie Martin)所寫 ,這意味着它可以出現在C語言語句的右側。這對於簡潔明了。
對於代碼混淆來說至關重要,如下所示:
Look-> See?!
No
:(
Oh, well
);
緊湊性以及將if-then-else構造內聯到表達式中的能力。
C中有很多東西在技術上是不需要的,因為就其他方面而言,它們或多或少可以輕松實現。 這是不完整的清單:
想象一下,如果沒有這些代碼,您的代碼將是什么樣子,您可能會找到答案。 三元運算符是“語法糖”的一種形式,如果謹慎和熟練地使用它,將使編寫和理解代碼更加容易。
有時,三元運算符是完成工作的最佳方法。 特別是當您希望三元的結果為l值時。
這不是一個很好的例子,但是我在更好的地方空白。 一件事是certian,雖然您仍然需要使用三進制,但是通常不需要真正使用三進制。
const char* appTitle = amDebugging ? "DEBUG App 1.0" : "App v 1.0";
我要警告的一件事是將三元串在一起。 他們成為真實的
維修時的問題:
int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;
編輯 :這是一個潛在的更好的例子。 您可以使用三元運算符來分配引用和const值,否則您將需要編寫一個函數來處理它:
int getMyValue()
{
if( myCondition )
return 42;
else
return 314;
}
const int myValue = getMyValue();
...可能成為:
const int myValue = myCondition ? 42 : 314;
更好的是一個有爭議的問題,我將選擇不辯論。
由於尚無人提及,因此獲取智能printf
語句的唯一方法是使用三元運算符:
printf("%d item%s", count, count > 1 ? "s\n" : "\n");
注意:從C轉到C ++時,運算符優先級會有所不同,並且可能會因此而產生的細微錯誤感到驚訝。
三元運算符是一個表達式,而不是一個語句,這一事實使得它可以在宏擴展中使用,作為函數的宏,這些宏用作表達式的一部分。 常量可能不是原始C的一部分,但是宏預處理器可以追溯到原來。
我見過它使用的一個地方是在一個數組包中,該包使用宏進行了綁定檢查的數組訪問。 經過檢查的引用的語法類似於aref(arrayname, type, index)
,其中arrayname實際上是指向結構的指針,該結構包括數組邊界和數據的無符號char數組,type是數據的實際類型,索引就是索引。 它的擴展很繁瑣(我不會從內存中完成),但是它使用了一些三元運算符來進行綁定檢查。
由於需要返回對象的多態性,因此不能將其作為C中的函數調用來進行。 因此,需要一個宏來在表達式中進行類型轉換。 在C ++中,您可以作為模板化的重載函數調用來執行此操作(可能對於operator []),但是C不具有此類功能。
編輯:這是我正在談論的示例,來自Berkeley CAD陣列軟件包(glu 1.4版)。 array_fetch用法的文檔為:
type
array_fetch(type, array, position)
typeof type;
array_t *array;
int position;
從數組中獲取元素。 嘗試在數組范圍之外進行引用時發生運行時錯誤。 沒有類型檢查,指定位置的值實際上是在取消引用數組時使用的類型。
這是array_fetch的宏定義(請注意,使用三元運算符和逗號排序運算符以正確的順序以正確的值執行所有子表達式,作為單個表達式的一部分):
#define array_fetch(type, a, i) \
(array_global_index = (i), \
(array_global_index >= (a)->num) ? array_abort((a),1) : 0,\
*((type *) ((a)->space + array_global_index * (a)->obj_size)))
array_insert的擴展(在必要時可以擴展數組,例如C ++矢量)的擴展更加困難,涉及多個嵌套的三元運算符。
它是語法糖,是僅包含一個語句的簡短if / else塊的便捷縮寫。 從功能上講,兩個構造應表現相同。
三元運算符可能比常規的else子句具有更高的性能,這在嵌入式應用程序中可能很關鍵,但編譯器優化可能會消除這種差異。
就像dwn所說的那樣,性能是復雜處理器興起期間的優勢之一,MSDN博客非經典處理器行為:如何比不做更快地做事給出了一個例子,清楚地表明了三元(條件)運算符與操作符之間的區別。 if / else語句。
給出以下代碼:
#include <windows.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
int array[10000];
int countthem(int boundary)
{
int count = 0;
for (int i = 0; i < 10000; i++) {
if (array[i] < boundary) count++;
}
return count;
}
int __cdecl wmain(int, wchar_t **)
{
for (int i = 0; i < 10000; i++) array[i] = rand() % 10;
for (int boundary = 0; boundary <= 10; boundary++) {
LARGE_INTEGER liStart, liEnd;
QueryPerformanceCounter(&liStart);
int count = 0;
for (int iterations = 0; iterations < 100; iterations++) {
count += countthem(boundary);
}
QueryPerformanceCounter(&liEnd);
printf("count=%7d, time = %I64d\n",
count, liEnd.QuadPart - liStart.QuadPart);
}
return 0;
}
不同邊界的成本差異很大且很奇怪(請參閱原始材料)。 而如果改變:
if (array[i] < boundary) count++;
至
count += (array[i] < boundary) ? 1 : 0;
現在,執行時間與邊界值無關,因為:
優化器能夠從三元表達式中刪除該分支。
但是在我的台式機Intel i5 cpu / windows 10 / vs2015上,我的測試結果與msdn博客完全不同。
使用調試模式時 ,如果/其他成本:
count= 0, time = 6434
count= 100000, time = 7652
count= 200800, time = 10124
count= 300200, time = 12820
count= 403100, time = 15566
count= 497400, time = 16911
count= 602900, time = 15999
count= 700700, time = 12997
count= 797500, time = 11465
count= 902500, time = 7619
count=1000000, time = 6429
和三元運營商成本:
count= 0, time = 7045
count= 100000, time = 10194
count= 200800, time = 12080
count= 300200, time = 15007
count= 403100, time = 18519
count= 497400, time = 20957
count= 602900, time = 17851
count= 700700, time = 14593
count= 797500, time = 12390
count= 902500, time = 9283
count=1000000, time = 7020
使用發布模式時 ,如果/其他成本:
count= 0, time = 7
count= 100000, time = 9
count= 200800, time = 9
count= 300200, time = 9
count= 403100, time = 9
count= 497400, time = 8
count= 602900, time = 7
count= 700700, time = 7
count= 797500, time = 10
count= 902500, time = 7
count=1000000, time = 7
和三元運營商成本:
count= 0, time = 16
count= 100000, time = 17
count= 200800, time = 18
count= 300200, time = 16
count= 403100, time = 22
count= 497400, time = 16
count= 602900, time = 16
count= 700700, time = 15
count= 797500, time = 15
count= 902500, time = 16
count=1000000, time = 16
三元運算符比我機器上的if / else語句慢!
因此,根據不同的編譯器優化技術,內部運算符和if / else的行為可能會大不相同。
C中一些更晦澀的運算符之所以存在,僅是因為它們允許將各種類似於函數的宏實現為返回結果的單個表達式。 我會說,這就是為什么主要目的?:
和,
運營商被允許存在,盡管它們的功能是多余的,否則。
假設我們希望實現一個類似於函數的宏,該宏返回兩個參數中的最大值。 然后將其稱為,例如:
int x = LARGEST(1,2);
將其實現為類似函數的宏的唯一方法是
#define LARGEST(x,y) ((x) > (y) ? (x) : (y))
if ... else
語句將無法實現,因為它不會返回結果值。 注意)
?:
的另一個目的是在某些情況下實際上提高了可讀性。 大多數情況下if...else
更具可讀性,但並非總是如此。 例如,使用長而重復的switch語句:
switch(something) { case A: if(x == A) { array[i] = x; } else { array[i] = y; } break; case B: if(x == B) { array[i] = x; } else { array[i] = y; } break; ... }
可以用可讀性更高的方法代替
switch(something) { case A: array[i] = (x == A) ? x : y; break; case B: array[i] = (x == B) ? x : y; break; ... }
請注意, ?:
永遠不會比if-else
導致更快的代碼。 這是由困惑的初學者創建的一個奇怪的神話。 在優化代碼的情況下, ?:
在大多數情況下具有與if-else
相同的性能。
如果有的話, ?:
可能比if-else
慢 ,因為它帶有強制的隱式類型提升,即使是將不使用的操作數也是如此。 但是?:
永遠不會比if-else
快。
注意)現在當然有人會爭論不解為什么不使用函數。 確實,如果可以使用函數,則它總是比類函數宏更可取。 但是有時候您不能使用函數。 例如,假設以上示例中的x
在文件范圍內聲明。 初始化程序必須是一個常量表達式,因此它不能包含函數調用。 其他必須使用類函數宏的實際示例涉及使用_Generic
或“ X宏”進行類型安全的編程。
三元= if-else的簡單形式。 它主要用於可讀性。
與...相同
if(0)
do();
if(0)
{
do();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.