reinterpret_cast와 C style cast

lmk378의 이미지

다음은 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가 발생합니다.

twinwings의 이미지

원하는 답변이 아니겠지만, 우선 오류를 내뱉는 원인은

OS수준에서 memory proctection 수행하는 것 때문인 것 같네요.

Test* 0 코드가 보이는데 즉, 0번지 부터 메모리를 Test 구조체로서 인식하겠다는 것인데,

보통 운영체제 수준에서 메모리 주소 - 0번지는 접근 못하게 해놓습니다.

좀 더 정확히 말하자면 운영체제에서 프로세스에게 특정한 메모리영역을 할당해 주는데

그 프로세스에게 속하지 않는 메모리영역을 참조하려고 할 시 운영체제단에서 memory protection을

수행합니다.(segmentaion fault 오류)

예를 들어, A란 프로그램내부에서 포인터를 이용해서 강제로 B 프로그램의 메모리 영역을 침범 할 수도 있을 텐데,

운영체제 수준에서 원천적으로 막아버리는 것이죠.

그리고 offset 값이 필요한 이유가 있나요?? 정말 로우레벨에서 건들어야 할게 아니라면,

멤버변수 이름 그 자체가 이미 오프셋 역할을 하기 때문에 이것만 잘 이용하면 컴파일러가

알아서 해줄텐데요..

lmk378의 이미지

필요에 의해서 작성한 코드는 아니고 오픈소스 라이브러리에 있는 코드입니다.
변수이름 자체가 오프셋 역할을 한다는건 무슨의미인가요?

익명 사용자의 이미지

지금 문제는 윗 분이 말씀하신 그런 게 아닙니다.

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) & 가 있느냐 없느냐에 따라서도 결과가 변합니다.

이건 뚜렷하게 이유를 모르겠네요.

lmk378의 이미지

먼제 제가 궁금한건 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으로 사용되고 있습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.