x86-64 코드에서 미묘한 충돌을 계산하는 데 단지 반나절을 소비합니다. 따라서 다른 사람에게는이 문제가 해결되었습니다.x86-64에서 포인터를 반환하는 선언되지 않은 함수는 잘못된 포인터 확장을 초래합니다.
올바른 선언없이 libc 함수를 사용하는 경우 gcc 은을 반환한다고 가정합니다. 예 : setlocale()은 int setlocale()이고 EAX에는 32 비트 int 값이 반환됩니다.
암시 적 또는 명시 적 형변환을 통해이 반환 값을 포인터로 변환하려고하면 호출 된 함수가 유효한 64 bin 포인터 값을 반환하더라도 부호 확장을 통해 32 비트에서 64 비트로 강제 변환됩니다. RAX! 예 :
char *p = setlocale(0, 0); // bear with me for a second
이
1c: b8 00 00 00 00 mov $0x0,%eax
21: e8 00 00 00 00 callq 26 <hard_locale+0x26>
26: 48 98 cltq ; <--- eax is expanded in rax
GCC로 컴파일됩니다 당신에게 말하려고조차 :
warning: initialization makes pointer from integer without a cast
당신은 문제를 보여줍니다 명시 적 캐스트에 경고 변경, 추가 할 경우 :
를warning: cast to pointer from integer of different size
'아무 일도 발생하지 않습니다, 운,하지만 메모리의 포인터까지의 큰 값을 반환 발생하는 경우 다음과 같이, 그것은, 엉망이됩니다
function returns in RAX: 0x07ffff7b9705e
cltq considers EAX with negative sign: 0xf7b9705e
now RAX is: 0xfffffffff7b9705e
을하고 포인터가 유효하지 않습니다.
수정 및 솔루션 :
항상 x86-64의 컴파일러에 기본적해야 적절한 함수 선언
-Wall -Werror를 사용합니다.
네가 사용하는 함수를 선언하지 않으면 나쁜 시간을 보게 될 것이다. 나는 당신이 할 수있는 한 많은 컴파일러 경고를 항상 가능하게 할 필요가 있다는 것이 잘 알려져 있다고 생각한다. 본질적으로 기본 유형 오류 인 셈플을 많이 쓰지는 않는다고 생각합니다. –
이것은 C에서 예상되는 동작입니다. 해결책은 컴파일러에서 발생하는 경고를 해결하는 것입니다.이 경고에는 "call 선언되지 않은 기능으로. " –
이 문제에 대한 비난의 대부분은 'int'를 32 비트로 유지하기로 결정한 컴파일러 작성자에게 맡겨야합니다. 'int'가 64 비트 인 64 비트 데이터 모델 (플랫폼의 자연적인 데이터 크기)은 상황을 잘 처리 할 것입니다. – ecatmur