2014-09-10 8 views
11

gcc에는 -Wcast-align 옵션이 있습니다.이 옵션은 타겟의 정렬이 증가하도록 포인터가 캐스팅 될 때마다 경고합니다. 이 PTR 8입니다 반면 내 컴퓨터에x86에서 char *에서 int * 로의 캐스트에 대해 -Wcast-align이 경고하지 않는 이유는 무엇입니까?

char data[10]; 
int ptr = *((int *)data); 

는, 데이터의 정렬 요구 사항은 1 :

여기 내 프로그램입니다.

왜 경고 메시지가 표시되지 않습니까?

x86 용으로 컴파일했기 때문일 수 있습니까?

+0

컴파일러는 아마 배열을 정렬하고 감지합니다. 포인터 매개 변수 대신'data + 1 '을 사용해보십시오. – Medinoc

+0

배열 포인터를 캐스팅하기 때문에 그것이라고 생각합니다. 데이터를 변수로 사용하여 코드를 실행 한 결과, 경고가 완벽하게 전달되었습니다. – Haris

+0

char * data = "aaaaa"; int ptr = * ((int *) data); 경고 메시지가 표시되지 않습니다. 내가 무엇이 누락 되었습니까? – linuxfreak

답변

14

Linux 용 i386 또는 x86-64 용으로 표준 ABI를 사용할 때 경고 메시지가 표시되지 않습니다. 왜 그런지 설명해 드리겠습니다.

첫째, gcc's documentation에 대한 -Wcast-align 말을 무슨 보자 : 포인터가 대상의 요구 정렬이 증가되도록 주조 할 때마다

이 경고. 예를 들어 정수가 2 바이트 또는 4 바이트 경계에서만 액세스 할 수있는 컴퓨터에서 char *int *으로 캐스팅되면 경고합니다.

인텔 아키텍처에서는 범용 명령어를 사용할 때 정수 정렬이 필요하지 않습니다. 더블 워드,

단어 및 quadwords 자연 경계의 메모리 으로 정렬 할 필요가 없습니다 : 장 단어의 4.1.1 정렬, 더블 워드, Quadwords, 더블 Quadwords, Intel's Basic Architecture manual에서 인용. 단어, 더블 워드, 및 쿼드 워드에 대한 자연 경계는 짝수 번호의 주소이며, 균등하게 나눌 수있는 주소는 이며, 주소는 각각 8로 나눌 수 있습니다. 그러나 프로그램의 성능을 향상 시키려면 이 가능할 때마다 (특히 스택) 데이터 구조가 자연 경계에 정렬되어야합니다.

따라서 정렬을 반드시 권장하지는 않지만 적극 권장합니다. 그러나이 규칙에는 한 가지 예외가 있습니다. EFLAGS 레지스터의 비트 18을 "정렬 검사"비트라고하며 CR0 레지스터의 비트 18을 "정렬 마스크"플래그라고합니다. 둘 다 1로 설정되면 "자연 경계"에 정렬되지 않은 데이터에 대한 모든 메모리 액세스 (단어의 경우 2 바이트, 더블 워드의 경우 4 바이트 등)는 #AC, 정렬 검사 예외 . 이에 대해 자세히 알아 보려면 Intel System Programming Guide을 확인하십시오.

그러나 System V ABI for i386System V ABI for x86-64은 EFLAGS의 정렬 플래그가 설정되어 있지 않습니다. 사실, I386 ABI는 29 페이지, 장 3-3 기계 인터페이스에 다음과 같은주의 사항 :

Intel386 아키텍처는 모든 데이터가 가 제대로 정렬로 액세스 할 필요가 없습니다. (...) 결과적으로 포인터가 참조 해제 또는 참조 인수와 같은 임의의 데이터 액세스는 이 올바르게 정렬되었거나되지 않을 수 있습니다. 잘못 정렬 된 데이터에 액세스하는 것은 올바르게 정렬 된 데이터에 액세스하는 것보다 느리며 그렇지 않으면 차이가 없습니다.

또한 권장되지만 :

컴파일러 적절한 배향과 독립적 인 데이터 객체를 할당한다.

GCC는 코드를 컴파일하는 플랫폼의 ABI를 항상 알고 있으며 - x86/64의 경우 - 정렬되지 않은 데이터 액세스가 허용된다는 사실을 알고 있습니다. 당신은 ARM의 GCC 툴체인이 코드를 컴파일하려고하면

int main(void) 
{ 
    char foo[] = "foobar"; 
    int bar = *(int*)(foo + 1); 
    return 0; 
} 

, 당신은 얻을 것이다 :이 같은 코드 정렬에 대한 경고없이 컴파일 이유 (의는 다음 예에 엄격한 앨리어싱 규칙에 대해 잊지하자)입니다 경고 :

[email protected]:/tmp$ arm-linux-gnueabi-gcc -Wcast-align align.c 
align.c: In function 'main': 
align.c:4:13: warning: cast increases required alignment of target type [-Wcast-align] 
    int bar = *(int*)(foo + 1); 

이것은 일반적으로 정렬되지 않은 액세스가 ARM에서는 가장 많이 피하기 때문입니다. 저는 ARM 전문가가 아니므로 그 이상의 것을 말할 수는 없습니다.

또한 대부분의 내용은 SSE/AVX에 적용되지 않습니다.

+0

맞습니다. ARM 용 gcc toolchain을 사용하여 컴파일하는 동안 작동합니다. – linuxfreak

+0

추가 정보 : 경고가 x86/x86-64 _anyway_에 표시되도록 할 수 있습니까? (크로스 컴파일 부족)? – imallett

+0

@imallett : 나는 GCC 문서에서 그런 것을 발견하지 못했다. 나는 완전히 새로운 질문을 게시하는 것이 낫다고 생각합니다. –