2014-10-08 8 views
1

나는 무슨 일이 일어나고 있는지를 알게 해주는 문제를 증류 시켰지만 여전히 그 이유는 분명하지 않다.컴파일러가 unsigned int로 SIGSEGV로 혼동되는 이유는 무엇입니까?

int main() { 
    unsigned int a = 2; 
    char c[2] = {}; 
    char* p = &c[1]; 
    return p[1 - a]; 
} 

마지막 줄을 다시 쓸 때 약간 선명합니다.

return *(p + (1 - a));  /* equivalent */ 
    return *(p + 1 - a);  /* works */ 
    return *(p + (1 - (int)a)); /* works */ 

저는 컴파일러가 괄호를 내부적으로 제거하지 않는다는 것에 놀랍니다. 그리고 더 명백하게 그것은 유형 unsigned int의 일시적인 부정적 결과를 보려고합니다. 그렇지 않으면 세그먼트 화 오류가 발생하지 않습니다. 어셈블러 출력에는 괄호가있는 코드와없는 코드 사이에 약간의 차이가 있습니다.

- movl $1, %eax 
- subl -12(%rbp), %eax 
- movl %eax, %edx 
+ movl -12(%rbp), %eax 
+ movl $1, %edx 
+ subq %rax, %rdx 
+1

'+'와'-'는 왼쪽 연관이므로'p + 1 - a'는'(p + 1) - a'와 같이 처리되어야합니다. 물론'p + a)' –

답변

3

이 모든 C 강제 변환 규칙에 관한 것입니다. 1-a이라는 표현식은 unsigned int으로 처리되며 언더 플로우가 발생합니다. 컴파일러는 유형을 혼합하기 때문에 괄호를 제거 할 수 없습니다. 귀하의 경우를 생각해

return *(p + (1 - a));  /* equivalent */ 

먼저 1-a을 계산하지만 unsigned int로 취급합니다. 그러면 부호없는 유형이 언더 플로우되고 unsigned int의 최대 값을 반환합니다. 이 포인터는 포인터에 추가되어, unsigned int이 32 비트 인 경우 p+(1<<31)과 같은 포인터를 참조 해제합니다. 이것은 유효한 메모리 위치가 될 가능성이 없습니다.

return *(p + 1 - a);  /* works */ 

p+1을 계산하고 p-1 역 참조 결과 a 그것으로부터 감산한다. 이것은 기술적으로 정의되지 않은 동작이지만 스택의 유효한 메모리 위치를 참조합니다 (대부분의 구현에서).

return *(p + (1 - (int)a)); /* works */ 

이 서명 inta 강제 변환 한 다음 -11-a을 계산합니다. 그런 다음 p-1을 참조 해제하십시오.

+0

이것은 어리석은 질문 일지 모르지만 초기에 '1'의 유형은 무엇입니까? 나는 결과가'a '때문에'unsigned int'로 변환된다는 것을 이해하지만 이론적으로'1'의 타입을 가질 수는 없습니다. 또는 이것은 단지'a'를 1 씩 줄이고 * 기본적으로 기호를 뒤집기위한 지시문으로 사용됩니다. –

+1

@pdknsk'1'의 타입은'signed int'이지만'unsigned int'로 강제 변환됩니다. [C99 표준] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) 섹션 6.3.1을 참조하십시오.8 (일반 산술 변환) : "그렇지 않으면 부호없는 정수 유형이있는 피연산자가 다른 피연산자 유형의 순위보다 크거나 같은 경우 부호있는 정수 유형의 피연산자는 다음과 같은 피연산자 유형으로 변환됩니다. 부호없는 정수 유형. " – sfstewman

+0

확장 설명 주셔서 감사합니다. –

5

문제는 당신이 UINT_MAX에 언더 플로우 1U - 2U이되도록 표현 1 - a에서 1unsigned int 승진 도착한다는 것입니다. take-home 메시지는 동일한 표현식에서 부호있는 및 부호없는 int를 혼합 할 때 항상 매우이어야한다는 것입니다.

좋은 컴파일러는 물론 활성화 경고를 제공하는 등 용도에 대해 경고 할 수 있습니다하지 않는 것이 :

main.c: In function 'int main()': 
main.c:5:19: warning: '*((void*)& c +4294967296)' is used uninitialized in this function [-Wuninitialized] 
    return p[1 - a];