2012-02-05 5 views
17

f0f1을 동일한 바이트에 포함하는 구현의 경우 아래 정의 된 프로그램이 있습니까?비트 필드 및 시퀀스 포인트

struct S0 { 
     unsigned f0:4; 
     signed f1:4; 
} l_62; 

int main (void) { 
     (l_62.f0 = 0) + (l_62.f1 = 0); 
     return 0; 
} 

나는 거기에 다른 생각을 할만한 이유가 있다면 C99와 C11에 대한 답에 흥미가 있습니다. 2 : 객체가 표현의 평가에 의해 최대 한번의 저장된 값 수정 된 Fi를 에드를 가진다 이전 및 다음 시퀀스 지점 사이

C99에서

은, 내가 찾은 모두 6.5이었다. [...]

이 단락이 위의 프로그램에 어떤 영향을 미치는지 분명하지 않습니다.

많은 수의 무작위 테스트를 기반으로 대부분의 컴파일러는 두 지정이 간섭하지 않는 코드를 생성하는 것으로 나타납니다.

+1

표준의 해당 부분은 나에게 두통을줍니다. 내 현재의 읽기 의도는 UB이다 (예를 들어 C11에서는 두 개의 스레드에서 두 개의 필드를 수정하는 과정이 동기화되지 않음), 6.5의 언어는 다른 것과 마찬가지로 비트 필드를 언급하는 것을 잊어 버린다. 비트 필드가 특별한 처리를하는 곳. – AProgrammer

+0

@AProgrammer : 위 코드는 명확한 논리적 의미를 지니 며 (쓰기가 순차적으로 발생하는 것처럼 처리합니다), 작성자가 둔기가 아닌 컴파일러가 해당 동작을 생성하는 코드를 생성해서는 안됩니다 단일 스레드의 경우. 표준 작성자가 UB가되도록 의도 한 그럴듯한 이유를 제안 할 수 있습니까? – supercat

답변

3

C11은 비트 필드가 동일한 메모리 위치의 일부인 인접한 으로 간주합니다. 이러한 비트 필드는 원자 적으로 업데이트되지 않을 수 있습니다. 즉, 하나의 업데이트가 다른 동작보다 먼저 명시 적으로 시퀀싱되지 않으면 동작이 정의되지 않습니다. 3.14 memory location에는 두 개의 필드가 서로 다른 메모리 위치에있는 것으로 간주 될 수있는 경우에 대한 자세한 설명이 있으므로이 필드에 대한 업데이트는 독립적으로 간주 될 수 있습니다.

당신이 두 개의 비트 필드 사이의 기괴한 "메모리 위치의 구분은"이

struct S0 { 
     unsigned f0:4; 
     int :0; 
     signed f1:4; 
} l_62; 

있도록 당신의 구조를 수정한다면

는 코드가 잘 보장 될 것이다.

C99의 경우 더 복잡한 것처럼 보입니다. 메모리 위치에 대한 자세한 개념은 없습니다. 리눅스 커널 메일 링리스트에 대한 최근의 논의에서 일반적으로 비트 필드의 모든 쌍에 대해 그들 중 하나를 업데이트 할 때 원 자성을 보장한다고 주장했다. 토론의 시작점은 gcc가 예기치 않은 방식으로 비트 필드에 인접한 비 비트 필드를 오염시켜 가짜 충돌로 이어지는 경우입니다.

+2

동일한 메모리 위치를 수정하는 것은 C11의 데이터 경쟁입니다. 그러나 5.1.2.4/4는 메모리 위치를 말하지만 6.5/2는 스칼라 객체 만 말합니다. 그리고 나는 그것이 감독이라는 것을 확신하지 못합니다. C++의 해당 문구는 비슷하지만 데이터 경주는 있지만 단일 스레드에서 단일 표현에 대해서는 UB가 아닙니다. – AProgrammer

+0

@AProgrammer : 동일한 저장소 요소의 서로 다른 비트 필드에 동시 (다른 스레드) 쓰기가 순차적으로 일관된 방식으로 작동하도록 명령하는 것은 대부분의 플랫폼에서 심각하게 비실용적입니다. 대부분의 플랫폼은 비용이 거의 들지 않으므로 한 필드의 쓰기가 다른 필드의 동시 읽기에는 영향을 미치지 않지만 모든 플랫폼에서 무료가 아니므로 표준에서 요구하지 않습니다. 그러나 컴파일러가 단일 스레드 케이스를 처리하지 않아야한다고 제안하는 것은 아무것도 없습니다. – supercat

0

여기서 할당은 구조체 멤버에 대한 것입니다. 동일한 저장소를 공유한다는 사실은 논리에 아무런 영향을주지 않습니다. 사실, 실제로 같은 일을하지 않았습니다.

물론 저는 언어 변호사가 아닙니다.