[英]C++ — return x,y; What is the point?
我已經用C和C ++編程了幾年,現在我剛剛開始學習大學課程而且我們的書有一個這樣的函數作為一個例子:
int foo(){
int x=0;
int y=20;
return x,y; //y is always returned
}
我從未見過這樣的語法。 事實上,我從來沒有見過的,
參數列表之外使用運營商。 如果y
總是返回,那么重點是什么? 是否有需要像這樣創建return語句的情況?
(另外,我也標記了C,因為它適用於兩者,盡管我的書特別是C ++)
根據C FAQ :
准確地說,逗號運算符在一般表達式中的含義
e1,e2
是“評估子表達式e1,然后評估e2;表達式的值是e2的值。” 因此,e1最好涉及賦值或增量++或減量 - 或函數調用或其他一些副作用,否則它將計算一個將被丟棄的值。
所以我同意你的觀點,除了說明這是有效的語法之外沒有其他意義,如果那樣的話。
如果你想用C或C同時返回值++,你可以創建一個struct
含有x
和y
成員,並返回結構來代替:
struct point {int x; int y;};
然后,您可以定義類型和幫助函數,以便在struct
輕松返回兩個值:
typedef struct point Point;
Point point(int xx, int yy){
Point p;
p.x = xx;
p.y = yy;
return p;
}
然后更改原始代碼以使用輔助函數:
Point foo(){
int x=0;
int y=20;
return point(x,y); // x and y are both returned
}
最后,你可以嘗試一下:
Point p = foo();
printf("%d, %d\n", p.x, p.y);
此示例在C和C ++中編譯。 雖然如Mark所示,在C ++中,您可以為point
結構定義構造函數,從而提供更優雅的解決方案。
另外,在支持它的Python語言中,直接返回多個值的能力非常好:
def foo():
x = 0
y = 20
return x,y # Returns a tuple containing both x and y
>>> foo()
(0, 20)
參數列表中的逗號僅用於分隔參數,與逗號運算符不同。 在您的示例中,逗號運算符計算x和y,然后拋棄x。
在這種情況下,我猜想嘗試返回兩個值並且不知道如何操作的人是錯誤的。
逗號運算符主要用於for
語句:
for( int i=0, j=10; i<10; i++, j++ )
{
a[i] = b[j];
}
第一個逗號不是逗號運算符,它是聲明語法的一部分。 第二個是逗號運算符。
這根本不能回答原始問題但可能對某些人感興趣,但是如果你想用C ++返回它們,你需要像這樣寫它(並且需要一個c ++ 0x編譯器) )
tuple<int, int> foo()
{
int x = 0;
int y = 20;
return make_tuple(x, y);
}
這樣訪問 -
tuple<int, int> data = foo();
int a = get<0>(data);
int b = get<1>(data);
struct Point {
int x, y;
Point(int x_) : x(x_), y(0) {}
Point(const Point& p) : x(p.x), y(p.y) {}
Point operator, (int y_) const { Point p=*this; p.y = y_; return p; }
};
Point get_the_point () {
int x = 0;
int y = 20;
return (Point)x, y;
}
:p
就像每個評論這里的人都認為這是毫無意義的一樣,我並不反對,只是看一下這個例子,我會猜測這不是更好:
作者正在收到關於x未在函數中使用的編譯器警告,這是讓警告消失的簡單方法。
此語法可用於保存if
語句的其他范圍括號。 例如,通常你會寫以下內容:
if (someThing == true)
{
a = 1;
b = 2;
return true;
}
這可以由以下內容代替:
if (someThing == true)
return a = 1, b = 2, true;
我認為這種編碼風格的使用是出於對冒充的沖動,而不是編寫干凈的代碼。
這是逗號運算符(,) 。
表達式x和y都被計算。 整體表達的結果是y,即后一個值。
很難說為什么在這里使用它。 我想,出於演示目的。 顯然,該功能可以重構為:
int foo()
{
return 20;
}
這看起來像是一個可怕的代碼示例。 它可能是C / C ++中的有效語法,但我想不出你為什么要這樣做的原因。
如果要返回x和y,在C ++中更好的方法是使用x和y屬性定義“Point”類或結構,並返回它。 另一種選擇是通過引用傳入x和y,然后在方法中適當地設置值。
如果方法只是返回y,我只會“返回y;”。 如果x需要在return語句之前“評估”,則應該在單獨的行上完成。
返回聲明沒有意義。
如果x
被聲明為volatile
,它將強制訪問(因為至少在C ++中對volatile
變量的引用被認為是外部可觀察的行為),但事實並非如此。
如果不是x
,而是存在某種帶副作用的計算,它會進行該計算,然后返回y
。 然而,非volatile
x
沒有副作用。 執行不需要執行任何沒有副作用或外部可觀察行為的代碼。 逗號運算符執行逗號左側的任何內容,忽略結果,並執行並保留右側的值(除非在這種情況下可以忽略運算符的左側)。
因此, return x, y;
聲明與return y;
完全相同return y;
。 如果x
不僅僅是一個完全沒有意義的事情,那么將它寫成x; return y;
會在風格上更好x; return y;
x; return y;
,這是完全相同的事情。 它不會那么令人困惑。
一方面,作者可能是一個誠實的錯誤。
另一方面,作者可能正在解釋語法上正確的正確代碼,而不是編譯器警告。
無論哪種方式,返回多個結果的唯一方法是定義一個類並使用它的實例,或者可能是一個數組或集合。
這是逗號運算符。 此類語法可用於禁用編譯器關於未使用的變量x
警告。
在for循環之外,這個comman操作符的另一個主要用戶(與函數調用版本相似)是在宏中,在執行某些操作后返回一個值。 現在這些是其他方法,但我認為comman運算符曾經是最干凈的方式。
#define next(A, x, y, M) ((x) = (++(y))%(M) , A[(x)])
請注意,這個宏通常是宏的一個不好的例子,因為它重復x並且可能由於其他原因。 以這種方式使用逗號運算符應該是罕見的。 您的書中的示例可能是嘗試使代碼示例適合該示例可用的行數。
我已經看到在C中使用這種語法在操作中途返回時進行內務處理。 絕對不可維護的代碼:
int foo(int y){
char *x;
x = (char*)malloc(y+1);
/** operations */
if (y>100) return free(x),y;
/** operations */
if (y>1000) return free(x),y;
}
本書試圖消除在C ++之前學習其他語言的人的混淆。 在許多語言中,您可以使用類似的語法返回多個值。 在C ++中,它將在沒有警告的情況下進行編譯(除非您指定-Wall
或-Wunused-value
),但如果您習慣使用其他語言,它將無法按預期方式工作。 它只會返回最后一個值。
然而,似乎作者引起的混淆比他預防的更多,因為在C ++的return語句中使用這種語法是沒有可讀的情況,除非意外地像其他語言一樣使用它。 他警告大多數人不會嘗試使用。 但是,如果你這樣做,那么調試會非常混亂,因為多重賦值語句int x, y = foo()
也可以很好地編譯。
底線:始終使用-Wall
並修復它警告你的內容。 C ++語法允許您編寫許多沒有意義的東西。
當與return
關鍵字一起使用時,逗號運算符返回最后一個值,這最初會讓人感到困惑,但可以使事情更簡潔 。
例如,以下程序將以狀態代碼2退出。
#include <iostream>
using namespace std;
void a() {
cout << "a" << endl;
}
int one() {
cout << "one" << endl;
return 1;
}
int zero() {
cout << "zero" << endl;
return 0;
}
int main() {
return one(), a(), zero(), 2;
}
使用以下內容編譯和執行時,您將看到下面的輸出。
michael$ g++ main.cpp -o main.out && ./main.out ; echo $?
one
a
zero
2
是否有需要像這樣創建return語句的情況?
IMO,我絕不會在書籍示例等函數中使用多個返回。 它違反了結構化設計。 不過,有很多程序員可以做到! 調試其他人的代碼我已經在每個return語句中為一個全局變量賦值,這樣我就可以找出執行的返回值。
重點是x的副作用(即逗號運算符的左側)。 有關詳細信息,請參閱Justin Ethier答案。
一個例子是C ++ 11中的constexpr函數,直到C ++ 14:這樣的函數可能不包含任意語句,而只包含一個return語句。
以下是CppCon 2016中Patrice Roys“異常情況”的代碼示例:
constexpr int integral_div(int num, int denom) {
return assert(denom != 0), num / denom;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.