2014-06-20 4 views
4

나는 쉼표로 두 인스턴스가 분리되어 있기 때문에 유효하다고 생각합니다. (일반적인 할당은 아니지만) 확신 할 수없고 검색은이 두 가지 특정 상황에 대해 어떤 것도 제기하지 않습니다.같은 줄에서 변수를 사용할 때 사전 증가 연산자

두 경우 모두 변수를 두 개의 병렬 배열에 대한 인덱스로 사용하고있었습니다.

int a[3] = {10, 20, 30}; 
int b[3] = {20, 40, 60}; 

상황 1 : 배열

struct testStruct { 
    int t1; 
    int t2; 
}; 
int i = 0; 
testStruct test = {a[++i], b[i]} 
최종 라인

예상 결과의 구조체를 초기화 : test = {20, 40}

상황 # 2 : 함수로서 배열에서 특정 값 전달 args

void testFunc(int t1, int t2) { 
    // do stuff 
} 
int i = 0; 
test(a[++i], b[i]); 

최종 결과 예상 결과 : test(20, 40)

유효한 코드인가요? 그리고 그렇다면 모든 컴파일러에서 유효합니까?

결과가 예상대로입니까? 그렇다면, 배열 때문이거나 쉼표로 인한 것입니까?

감사합니다.

첫번째 코드 니펫
+2

상황 하나 콤마 연산자 아니지만 시퀀스 지점이 참조 [정의되지 않은 동작이 사전에 C 초기화 목록 내의 동일 변수의 여러 돌연변이인가 ++ 11] (http://stackoverflow.com/questions/19881803/are-multiple-mutations-of-the-same-variable-within-initializer-lists-undefined-b) 및 [이니셜 라이저 내의 여러 변형은 정의되지 않은 동작입니까? ] (http://stackoverflow.com/questions/14442894/are-multiple-mutations-within-initializer-lists-undefined-behavior) ... 상황 2는 쉼표 연산자가 아닌 정의되지 않은 동작입니다. –

+0

링크를 가져 주셔서 감사합니다. 나는 그 용어를 검색하지 못했을 것입니다. 적어도 첫 번째 인스턴스가 작동한다는 것을 알면 기쁩니다. – Simca

+0

첫 번째 인스턴스 인 pre C++ 11에서는 평가 순서가 지정되어 있지 않음을 알고 있어야합니다. 나는 까다로운 코드에 대해 조언 할 것이고, {a [i], b [i + 1]} 등을 할 수 있고 이후에 'i'를 증가 시키면 표준의 이상한 모서리에 대해 걱정할 필요가 없을 것이다. –

답변

4

장기간에 걸쳐 이러한 "트릭"을 코드에 사용하는 것에 대한 조언은 유지 보수의 악몽이며 추론하기가 어렵습니다. 이 대안은 예를 들어,이 코드는 거의 항상 :

testStruct test = {a[++i], b[i]} 

가 변경 될 수 있습니다 :

++i ; 
testStruct test = {a[i], b[i]} 

그래서 어느 경우 함수 호출 모두에서 쉼표 연산자를 사용했다 가졌 및 초기화 데이터는 쉼표를 나열 문법 요소이며 다른 것은 없습니다.

첫 번째 상황은 C++ 11인지 C++ 11인지에 따라 몇 가지주의 사항이 있지만 잘 정의되어 있습니다.

두 경우 모두 각 C 쉼표 다음에 순서 점이 있지만 사전 C++ 11에서는 평가 순서가 지정되지 않습니다. 그래서 우리는 defect report 430로 이동하여 사전 C++ (11)의 경우이를 볼 수 있다고한다 :

은 최근 GCC 버그 보고서 ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633가)

int count = 23; int foo[] = { count++, count++, count++ }; 

의 유효성에 대해 묻는

이입니다 정의되지 않았거나 지정되지 않았습니까?

과 대답은 (강조 광산 앞으로가는) :

나는 표준 가 위의 각 이니셜 표현 전체 표현 (1.9 [소개 인 것은 분명하다 생각 .execution]/12-13 또한 문제 392를 참조하십시오. 따라서 각 표현 다음에 시퀀스 포인트가 있습니다 (1.9 [소개. 실행]/16). 나는 표준이 이 표현식이 평가되는 순서를 지시하지 않는 것 같음에 동의한다., 그리고 아마도 그렇다. 누구든지 컴파일러를 알지 못한다면 왼쪽에서 오른쪽으로 표현식을 평가할 수 있습니까? C에서

++ (11)는 말한다 섹션 8.4.5 단락의 draft C++11 standard에 구워 : 포함 보강-초기화 목록의 초기화 목록 내에서

을의 초기화-조항, 팩 확장으로 인한 결과 (14.5.3), 은 표시된 순서대로 평가됩니다. 즉, 모든 값 계산과 부작용이 주어진 initializer-clause은 모든 값 계산 전에 배열되고 부작용은 의 쉼표로 구분 된 이니셜 라이저 목록 .

시퀀싱의 문구가 다양하지만 결론은 동일하지만 나머지 콘텐츠에 대한 대답은 변경되지 않으므로 앞으로 C++ 11로 진행될 예정입니다.

두 번째 상황은 함수에 대한 인수 평가 순서가 지정되지 않았으므로 해당 평가가 서로에 대해 불확실한 순서로 지정되어 있으므로 undefined behavior을 호출합니다. 명시된 경우를 제외하고

, 개인 사업자 의 개인 표현의 하위 표현식의 피연산자의 평가가 unsequenced 있습니다 : 우리는 말한다 섹션 1.9 제 에서이 정의되지 않은 동작을 볼 수 있습니다. [ 참고 : 프로그램 실행 중에 두 번 이상 평가되는 식에서는 순서가 지정되지 않고 불확정하게 시퀀스가 ​​지정됩니다. 하위 식에 대한 평가는 서로 다른 평가에서 일관되게 수행 할 필요가 없습니다. -end note] 연산자의 결과 인 의 값 계산은 연산자 결과 인 이 계산되기 전에 순서가 지정됩니다. 동일한 스칼라 개체의 다른 부작용 또는 동일한 스칼라 개체의 값을 사용하는 값 ​​계산과 관련하여 스칼라 개체의 부작용이 순으로 정렬되지 않은 경우 동작은 정의되지 않음입니다.

다음과 같은 예를 제공

f(i = -1, i = -1); // the behavior is undefined 
2

testStruct test = {a[++i], b[i]}; 

인 유효 (세미콜론을 추가하는 경우) 때문에 보강-INIT-리스트의 초기화리스트 이내 C++ 표준

4 항 팩 확장 (14.5.3)의 결과를 포함하여 initializer-clauses가 표시된 순서대로 평가됩니다. 즉, 모든 값 계산 및 부작용이 주어진 initializer-clause와 관련된 모든 값 계산 및 부작용이 후속되는 이니셜 라이저 절과 연관된 이니셜 라이저 목록의 쉼표로 구분 된 목록 에 있습니다.

컴파일러 GCC의 4.8.1가있다 (또는 적어도 한) 것을 고려 설명은 당신이의 예를 들어 서비스를 사용하여 평행 이동을 할 수 러시아어로 작성하지만 내가

here 을 설명 버그를 타고 두 번째 코드는

test(a[++i], b[i]); 

것은 보증되지 동작을 니펫을 그러나

을 "번역"goofle 때문에 evaluati의 순서 함수 인자의 on은 명시되지 않았다.

당신은 표현이 잘 형성 될 것이다이 경우 대신

test({ a[++i], b[i] }); 

을 작성할 수 있습니다.

+1

* 불특정 다수가 공개되지 않은 상태에서 불확실한 서열이 결정될 수 있습니다. 함수 인수가 * 순차적이지 않다고 말하는 것 같습니다. (1.9p13). – ecatmur

+0

@ecatmur 나는 인수의 평가 순서가 명시되지 않았다는 것을 의미한다. 두 컴파일러를 사용하면 다른 결과를 얻을 수 있으므로 정의되지 않은 동작이 발생합니다. 결과는 정의되지 않습니다. –

+1

지정되지 않은 동작은 정의되지 않은 동작과 다릅니다 (1.3.24 vs. 1.3.25). 이 경우 동작은 지정되지 않고 정의되지 않습니다. – ecatmur