문제
C++에서 쉼표 연산자는 어떻게 작동하나요?
예를 들어 다음과 같이 하면:
a = b, c;
a는 결국 b 또는 c와 같습니까?
(예, 테스트하기 쉽다는 것을 알고 있습니다. 누군가가 답을 빨리 찾을 수 있도록 여기에 문서화하면 됩니다.)
업데이트: 이 질문은 쉼표 연산자를 사용할 때 미묘한 차이를 드러냈습니다.이것을 문서화하려면 다음을 수행하십시오.
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
이 질문은 실제로 코드의 오타에서 영감을 받았습니다.무엇을 의도했는가
a = b;
c = d;
로 변하다
a = b, // <- Note comma typo!
c = d;
해결책
그것은 같을 것입니다 b
.
쉼표 연산자는 할당보다 우선순위가 낮습니다.
다른 팁
C++에서는 쉼표 연산자가 오버로드될 수 있다는 점에 주의하세요.따라서 실제 동작은 예상한 동작과 매우 다를 수 있습니다.
예로서, 부스트스피릿 기호 테이블에 대한 목록 초기화를 구현하기 위해 쉼표 연산자를 매우 영리하게 사용합니다.따라서 다음 구문을 가능하고 의미있게 만듭니다.
keywords = "and", "or", "not", "xor";
연산자 우선순위로 인해 코드는 (의도적으로!) 다음과 동일합니다.
(((keywords = "and"), "or"), "not"), "xor";
즉, 호출된 첫 번째 연산자는 다음과 같습니다. keywords.operator =("and")
나머지 프록시 객체를 반환합니다. operator,
s가 호출됩니다:
keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
쉼표 연산자에는 가장 낮은 모든 C/C++ 연산자의 우선순위.따라서 이는 항상 표현식에 바인딩되는 마지막 항목입니다. 즉, 다음과 같습니다.
a = b, c;
다음과 같습니다:
(a = b), c;
또 다른 흥미로운 사실은 쉼표 연산자가 시퀀스 포인트.이는 다음 표현식을 의미합니다.
a+b, c(), d
세 개의 하위 표현식(a+b, 씨() 그리고 디) 순서대로 평가됩니다.부작용이 있는 경우 이는 중요합니다.일반적으로 컴파일러는 적합하다고 판단되는 순서에 따라 하위 표현식을 평가할 수 있습니다.예를 들어, 함수 호출에서:
someFunc(arg1, arg2, arg3)
인수는 임의의 순서로 평가될 수 있습니다.함수 호출의 쉼표는 다음과 같습니다. ~ 아니다 운영자;그들은 구분 기호입니다.
쉼표 연산자:
- 우선순위가 가장 낮습니다
- 왼쪽 결합적이다
쉼표 연산자의 기본 버전은 모든 유형(내장 및 사용자 정의)에 대해 정의되며 다음과 같이 작동합니다. exprA , exprB
:
exprA
평가된다- 결과
exprA
무시된다 exprB
평가된다- 결과
exprB
전체 표현식의 결과로 반환됩니다.
대부분의 연산자에서는 컴파일러가 실행 순서를 선택할 수 있으며 최종 결과에 영향을 주지 않으면 실행을 건너뛰어야 합니다(예: false && foo()
통화를 건너뜁니다. foo
).그러나 쉼표 연산자의 경우에는 해당되지 않으며 위의 단계는 항상 발생합니다.*.
실제로 기본 쉼표 연산자는 세미콜론과 거의 동일한 방식으로 작동합니다.차이점은 세미콜론으로 구분된 두 표현식이 두 개의 개별 명령문을 형성하는 반면, 쉼표로 구분하면 모두 단일 표현식으로 유지된다는 것입니다.이것이 바로 다음과 같은 시나리오에서 쉼표 연산자가 사용되는 이유입니다.
- C 구문에는 단일이 필요합니다. 표현, 주장이 아닌.예를 들어~에
if( HERE )
- C 구문에는 단일 명령문이 필요합니다.초기화에서는
for
고리for ( HERE ; ; )
- 중괄호를 건너뛰고 단일 명령문을 유지하려는 경우:
if (foo) HERE ;
(그러지 마세요. 정말 추악합니다!)
명령문이 표현식이 아닌 경우 세미콜론을 쉼표로 대체할 수 없습니다.예를 들어 다음은 허용되지 않습니다.
(foo, if (foo) bar)
(if
표현이 아닙니다)- int x, int y(변수 선언은 표현식이 아님)
귀하의 경우에는 다음이 있습니다.
a=b, c;
, 동등a=b; c;
, 가정a
쉼표 연산자를 오버로드하지 않는 유형입니다.a = b, c = d;
에 해당a=b; c=d;
, 가정a
쉼표 연산자를 오버로드하지 않는 유형입니다.
모든 쉼표가 실제로 쉼표 연산자는 아닙니다.완전히 다른 의미를 갖는 일부 쉼표는 다음과 같습니다.
int a, b;
--- 변수 선언 목록은 쉼표로 구분되어 있지만 쉼표 연산자는 아닙니다.int a=5, b=3;
--- 이것은 또한 쉼표로 구분된 변수 선언 목록입니다.foo(x,y)
--- 쉼표로 구분된 인수 목록입니다.사실은,x
그리고y
에서 평가할 수 있다 어느 주문하다!FOO(x,y)
--- 쉼표로 구분된 매크로 인수 목록foo<a,b>
--- 쉼표로 구분된 템플릿 인수 목록int foo(int a, int b)
--- 쉼표로 구분된 매개변수 목록Foo::Foo() : a(5), b(3) {}
--- 클래스 생성자의 쉼표로 구분된 초기화 목록
* 최적화를 적용하면 이는 전적으로 사실이 아닙니다.컴파일러가 특정 코드 조각이 나머지 코드에 전혀 영향을 미치지 않는다는 것을 인식하면 불필요한 명령문을 제거합니다.
의 가치 a
될거야 b
, 그러나 값은 표현식 될거야 c
.즉,
d = (a = b, c);
a는 다음과 같다 b
, 그리고 d
같을 것이다 c
.
b의 값은 a에 할당됩니다.C에게는 아무 일도 일어나지 않을 것이다
쉼표 연산자는 할당 연산자보다 우선순위가 낮으므로 a의 값은 b와 같습니다.
예 쉼표 연산자는 할당 연산자보다 우선순위가 낮습니다.
#include<stdio.h>
int main()
{
int i;
i = (1,2,3);
printf("i:%d\n",i);
return 0;
}
출력 :나는=3
쉼표 연산자는 항상 가장 오른쪽 값을 반환하기 때문입니다.
할당 연산자가 있는 쉼표 연산자의 경우:
int main()
{
int i;
i = 1,2,3;
printf("i:%d\n",i);
return 0;
}
출력:나는=1
우리가 알고 있듯이 쉼표 연산자는 할당보다 우선순위가 낮습니다.....
먼저 첫 번째 것들: 쉼표는 실제로 연산자가 아닙니다. 컴파일러의 경우 의미를 갖는 토큰일 뿐입니다. 문맥 다른 토큰과 함께.
이것이 무엇을 의미하며 왜 귀찮게 합니까?
예시 1:
다른 맥락에서 동일한 토큰의 의미 차이를 이해하기 위해 다음 예를 살펴보겠습니다.
class Example {
Foo<int, char*> ContentA;
}
일반적으로 C++ 초보자는 이 표현식이 사물을 비교할 수 있다고 생각하지만 이는 완전히 잘못된 것입니다. <
, >
그리고 ,
토큰은 사용 상황에 따라 다릅니다.
물론 위 예의 올바른 해석은 템플릿의 구현이라는 것입니다.
예시 2:
일반적으로 하나 이상의 초기화 변수 및/또는 루프의 각 반복 후에 수행되어야 하는 하나 이상의 표현식을 사용하여 for 루프를 작성할 때 쉼표도 사용합니다.
for(a=5,b=0;a<42;a++,b--)
...
쉼표의 의미는 사용 상황에 따라 다릅니다. 여기서는 쉼표의 의미입니다. for
건설.
문맥상 쉼표는 실제로 무엇을 의미하나요?
(C++에서 항상 그렇듯) 더 복잡하게 만들기 위해 쉼표 연산자 자체가 오버로드될 수 있습니다. 콘라드 루돌프 그것을 지적하기 위해).
질문으로 돌아가서, 코드
a = b, c;
컴파일러에 대한 의미는 다음과 같습니다.
(a = b), c;
왜냐하면 우선 사항 ~의 =
토큰/연산자가 우선순위보다 높습니다. ,
토큰.
그리고 이것은 다음과 같은 맥락으로 해석됩니다.
a = b;
c;
(해석은 컨텍스트에 따라 달라지며 여기서는 함수/메서드 호출이나 템플릿 인스턴스화가 아닙니다.)