reinterpret_cast와 C style cast
글쓴이: lmk378 / 작성시간: 월, 2014/11/03 - 6:01오후
다음은 Test 구조체의 각 인덱스값을 구하는 코드입니다.
#include <iostream> struct Test { char *name; int age; }; int main() { size_t offset1 = (size_t)&reinterpret_cast<const volatile char&>(((Test *)0)->age); std::cout << offset1 << std::endl; size_t offset2 = (size_t)&(const volatile char&)(((Test *)0)->age); std::cout << offset2 << std::endl; std::cin.get(); return 0; }
visual studio 2013에서 컴파일 했을 경우
offset1의 경우 문제없이 잘 동작하는데 offset2에서는 access violation error가 발생합니다.
두 코드상 왜 이런 차이점이 있을까요?
추가.
g++ 4.8.1에서 컴파일 했을 경우
offset1, offset2 모두 문제없이 잘 동작하지만 offset2는 volatile을 제거하면 segmentaion fault가 발생합니다.
Forums:
제가 알고 있기론..
원하는 답변이 아니겠지만, 우선 오류를 내뱉는 원인은
OS수준에서 memory proctection 수행하는 것 때문인 것 같네요.
Test* 0 코드가 보이는데 즉, 0번지 부터 메모리를 Test 구조체로서 인식하겠다는 것인데,
보통 운영체제 수준에서 메모리 주소 - 0번지는 접근 못하게 해놓습니다.
좀 더 정확히 말하자면 운영체제에서 프로세스에게 특정한 메모리영역을 할당해 주는데
그 프로세스에게 속하지 않는 메모리영역을 참조하려고 할 시 운영체제단에서 memory protection을
수행합니다.(segmentaion fault 오류)
예를 들어, A란 프로그램내부에서 포인터를 이용해서 강제로 B 프로그램의 메모리 영역을 침범 할 수도 있을 텐데,
운영체제 수준에서 원천적으로 막아버리는 것이죠.
그리고 offset 값이 필요한 이유가 있나요?? 정말 로우레벨에서 건들어야 할게 아니라면,
멤버변수 이름 그 자체가 이미 오프셋 역할을 하기 때문에 이것만 잘 이용하면 컴파일러가
알아서 해줄텐데요..
필요에 의해서 작성한 코드는 아니고 오픈소스
필요에 의해서 작성한 코드는 아니고 오픈소스 라이브러리에 있는 코드입니다.
변수이름 자체가 오프셋 역할을 한다는건 무슨의미인가요?
?
지금 문제는 윗 분이 말씀하신 그런 게 아닙니다.
0번 주소에 액세스하면 당연히 할당 안했으니 segmentation fault 뜨는거고(굳이 0번이 아니더라도)
문제는 volatile 을 넣을때와 뻈을 때 왜 그런 차이가 있냐는 것이 핵심입니다.(gcc 기준)
원래 저런 식으로 코드를 짜면 보통은 아래와 같은 코드가 생성됩니다.
mov eax, 0
mov eax, dword ptr [eax+4] (4는 age 가 구조체에서 위치하는 곳)
이러면 당연히 0x4 주소에 액세스해서 값을 가져오려고 하니 에러가 나는게 당연합니다.
그런데 volatile 을 넣게 되면 이런 코드가 생성됩니다.
mov eax, 0
add eax, 4
사실 지금 괄호는 이렇게 되어 있습니다.
(size_t) &(const volatile char&) ( ( (Test *)0 )->age );
0번 주소 포인터에 간접액세스 하는 건 캐스팅에 관계가 없는 연산인데
이상하게도 volatile 의 여부에 따라 코드는 변하고 있습니다.
또한 앞의 (size_t) & 가 있느냐 없느냐에 따라서도 결과가 변합니다.
이건 뚜렷하게 이유를 모르겠네요.
먼제 제가 궁금한건 reinterpret_cast와
먼제 제가 궁금한건 reinterpret_cast와 C style cast가 컴파일러에서 왜 다른 코드를 생성하는가 입니다.
두번째로는 g++환경에서 reinterpret_cast는 volatile 여부와 관계없이 정상작동하지만 C 스타일 케스팅에서는 volatile의 여부가 차이를 만드는가 입니다.
// stddef.h
#define offsetof(s,m) (size_t)&reinterpret_cast((((s *)0)->m))
...
size_t size = offsetof(Test, age);
Test 구조체의 멤버변수 age에 해당하는 offset을 구하기 위한 define으로 사용되고 있습니다.
댓글 달기