extern "C" 에 대한 오해

jeongheumjo의 이미지

제가 여태 extern "C" 라는 키워드가 나오면 그 키워드의 영향을 받는 블록은 C의 문법으로 컴파일된다 라고 잘못 알고 있었습니다.
책을 다시 보니 저 키워드의 의미는 '네임 맹글링을 하지 말라' 라고 설명되어 있군요!

몇년간 잘못알고 살아왔습니다.
지금은 제가 제대로 이해한 것일까요?
혹시 더 깊은 의미가 있을까요?
혹, 저처럼 잘못알고 계션던 분 없으신가요? ^^;

cleol의 이미지

extern 은 "링크 규칙 (linkage)"을 정하기 위한 키워드입니다.
extern 이 없으면 기본적으로 변수는 모듈(.cpp 파일) 안에서만 참조할 수 있는 internal linkage 를 갖게 되고,
extern 을 붙여주면 external linkage 를 갖게 되서 다른 모듈에서 링크할 수 있습니다.
함수의 경우는 extern 이 없으면 기본적으로 external linkage 입니다. static 을 붙여서 internal 로 만들 수 있습니다.
외부 모듈이 링크를 할 수 있게 해주려면 링크하려는 대상을 찾을 수 있도록 해줘야 합니다.
C++ 프로그램에서 extern 은 extern "C++" 과 같은 뜻입니다.
extern 으로 마크된 이 "이름"을 찾아 링크하려고 시도할 녀석이 C++ 이라는 겁니다.
즉, C++ 프로그램이 이 이름을 찾아 링크할 수 있도록 하라는 뜻입니다.
마찬가지로 어떤 이름을 extern "C" 로 마크하면 C 모듈에서 이 녀석을 찾아서 링크할 수 있도록 하라는 겁니다.
C++ name mangling 을 하면 외부의 C 모듈에서 링크할 수 없습니다.
C 모듈은 C++ name mangling 규칙을 모르니까요.
따라서 extern "C" 를 써주면 name mangling 을 하지 않습니다.
gcc 는 gcj 를 통해 자바와 링크할 수 있어서 extern "Java" 도 가능합니다.
gcj 로 컴파일된 자바 모듈이 찾아서 링크할 수 있도록 하라는 거지요.
뭐 기술적/실용적 이유에서 사실상 대부분의 컴파일러가 extern "C++" 과 extern "C" 만 지원하지만,
extern "X" 의 "X" 자리에 어떤 언어든, 또는 이름 찾는 규칙(calling convention)이든 올 수 있습니다.

jeongheumjo의 이미지

이런 얘기 처음 들었습니다.
아마 컴퓨터공학과나 전산과 혹은 CS 라 불리는 전공을 공부하셨나봐요.
그쪽 학과에서는 컴파일러에 대해 이렇게 자세하게 배우죠?
저는 프로그램관련해서 공부하는 방법이 주로 서점의 프로그램 책들이거든요..
그 책들은 주로 기초적인 문법 위주로만 설명하고 있기 때문에 이런 내용을 제가 접할 수는 없었던 것 같습니다.
프로그래머라면 님처럼 해박하게 알 수 있어야 할 것 같은데요..
그런 지식은 어디에서 찾을 수 있을까요?
C++ 표준 스펙은 어려울 것 같고요..
아마도 C++ 창시자가 쓴 책과 같은 고급 문법책을 참고하면 될까요?

winner의 이미지

수업진행은 해야하니까 기초적인 문법은 가르치지만 까다롭거나 잘 안 쓰이는 문법은 다 알아서 공부해야 합니다.
extern "C"를 제가 처음 본 것은 Stephen Prata의 C++ Primer Plus 였는데 자세히 다루지는 않았었습니다.

하지만 컴퓨터공학 정규수업이 필요없다는 이야기는 절대 아닙니다. 전공자가 아니어도 스스로 공부해서 더 해박하신 분들도 있지만 대부분 비전공자와 관점의 차이를 느끼는 경우가 많았습니다.

잘 찾아보시면 원하시는 것을 다루는 도서들이 있을 겁니다. 대게 인기가 없어서 절판되는 경우가 많습니다만... ^_^

jeongheumjo의 이미지

공유 라이브러리를 만들 때는 꼭 C 모듈만을 위하지는 않지 않나요?
제가 읽은 책에서는 C++ 컴파일러의 네임맹글링을 피하기 위해 공유라이브러리에서 export 하는 함수,변수,클래스,클래스 함수 를 선언할 때 extern "C" 로 마크한다고 설명했거든요.
즉, 같은 C++ 모듈에서 사용될 공유라이브러리를 만들 때도 그 라이브러리를 사용하는 코드가 컴파일될 때 컴파일러의 버전에 따라 네임 맹글링 규칙이 다르고 그래서 공유라이브러리에서 export 하는 함수에서는 네임맹글링을 하지 않는 이름으로 export 해야 한다고 했거든요..
즉, export "C" 가 꼭 C 모듈을 위한 것은 아니라는 것이죠. 같은 C++ 모듈에서 사용되는 경우에도 각 컴파일러마다 다른 네임맹글링에 의한 링크 에러가 나는 걸 막기위해 쓰는 것이라고요.. 그리고 더 중요한 것은 extern "C" 로 마크해서 export 하는 것이 비단 함수뿐만이 아니라 클래스와 클래스 함수도 포함되거든요. 클래스와 클래스 함수는 C 에는 없는 것이니까 export "C"가 C 모듈과 link 될 수 있도록 하는 것은 아니라는 얘기입니다. 그래서 제가 놀랐던 것이구요..

마찬가지로 어떤 이름을 extern "C" 로 마크하면 C 모듈에서 이 녀석을 찾아서 링크할 수 있도록 하라는 겁니다.

아마 님께서도 C 모듈과만 link 될 수 있도록 하는 것이다라는 말씀은 아니셨을 것이라 생각합니다.

그리고 참고로 제가 공유라이브러리라고 말씀드렸는데 더 정확히는 DLL 에서의 얘기입니다. 그러니까 윈도우즈에서의 얘기이죠.. 하지만 extern "C" 의 문법이 플랫폼에따라 달라지지는 않을거라 생각합니다.

winner의 이미지

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf
의 7.5를 읽어보시기 바랍니다. 네, 죄송하게도 영어구요. 개정중인 C++ 표준안이라서 생소한 용어도 상당히 많을 겁니다.

C, C++ 표준은 참조구현이라는게 없어서 platform에 따라 달라지는 것이 많습니다. 표준에서 정의를 가장 명확히 하는 것은 compile 단계이고, 전처리나 link 단계는 의도적으로(?) 명확히 정의하지 않은 것이 많죠.
다른 언어로 작성된 object file과의 연결이라던가 전처리의 모든 것을 명확하게 작성한다는 것이 표준의 범위를 벗어나기 때문일 겁니다.

표준을 명확히 보여줄려고 할 때 책에서는 Comeau Compiler를 이야기합니다. 그야말로 표준을 지킬려고 만든 compiler 이니까요.

jeongheumjo의 이미지

역시 표준을 모르면 스펙을 정확히 이해하는 것이 어려운 것 같습니다.
7.5절을 읽어봤습니다.
제가 영어를 잘 못하지만 하나는 확실하게 알 수 있었습니다.
extern "C" 라고 했다고 해서 반드시 C language linkage 가 된다는 건 아니라는 것입니다.
다양한 예외상황이 있었네요..

A C language linkage is ignored for the names of class members and the member function
type of class member functions.

이제 이해했습니다.

네임맹글링 현상에 의한 링크 오류를 방지하기 위해서는 extern "C" 를 써서 C language linkage 로 심벌 이름이 생성되도록 해 하는데, 주의할 것은 extern "C" 에 의해 정말 C language linkage 가 적용되는가 하는 것을 확인해 볼 필요가 있다는 것입니다. 위 예에서 처럼 클래스에 대해서는 C language linkage 가 무시되고 C++ language linkage 가 적용되니까요..

네임맹글링 현상까지 고려할 필요 없는 경우에는( 공유라이브러리를 사용하는 모듈에서 언제나 공유라이브러리와 같은 컴파일러 같은 버전을 쓰는게 보장되면 ) extern "C" 를 쓸 필요는 없다. 하지만 그렇지 않은 환경에서는(해당 공유라이브러리를 사용하는 코드를 컴파일할 때 어떤 컴파일러를 쓸지 모르는 경우) extern "C" 로 C language linkage 를 사용할 수 있는 함수만(변수까지) 공유라이브러리에서 export 하도록 하는 것이 좋은 라이브러리 구현 방법일 것이다....

결국 공유라이브러리에서 공유할 수 있는 것은 네임맹글링 현상을 고려했을 때, C language linkage 가 될 수 있는 함수와 변수까지라는게 제 개인적인 결론입니다. 클래스, 네임스페이스, 클래스 함수 등은 네임맹글링에 의한 오류를 해결할 수 있는 방법을 깨닫게 되기전까지는 사용치 않아야 겠습니다.

컴파일러별, 각 컴파일러 버전별로 공유라이브러리를 만든다면 C++ language linkage 를 사용할 수 있겠다는 생각이 드네요.. 실제로 표준 C++ 라이브러리 등이 그렇지 않나 싶기도 하구요...

이런 개인적인 결론에 이르게 도와주셔서 감사드립니다. ^^;

cleol의 이미지

사실 extern "C" 를 사용해서 다른 컴파일러로 컴파일된 오브젝트 파일을 링크하는 것은 편법입니다.
C++이 "C 가 이름 찾는 규칙"을 알기때문에 사용할 수 있는 편법이지요.
하지만 말씀하셨듯이 어차피 C가 모르는 오브젝트 (클래스처럼 ) 에 대한 이름이면 extern "C" 는 무시될 수 밖에 없고,
이런 편법도 사용할 수 없습니다.
이는 C++0x 에서도 해결되지 않은 것으로 압니다.
실용적으로 중요한 문제이지만, implementation detail 으로 간주하고 그냥 두었던 부분을 이제와서 강제하기에는
컴파일러들이 이미 되돌아올 수 없는 강을 건너 한참을 간 것이지요.
그리고 저는 전산 전공자가 아닙니다.
저도 어떤 책에서 extern 에 대해서 공부했는지 잊어먹었는데...^^;
전산과에서도 어차피 같은 책으로 공부합니다.
그냥 이것 저것 많이 찾아 읽으시면 됩니다.
단 영어 자료를 충분히 읽을 수 있어야 합니다.
불행히도 고급 문서는 여전히 영어 자료가 좋은 것이 많습니다...

jeongheumjo의 이미지

위키피디아만 해도 필요한 정보는 한국판에는 없어서 결국 영문 위키피디아를 볼 수밖에 없으니까요...
우리가 영어를 쓴다면 나라가 갑자기 선진국이 될 수도 있을텐데..
언어에 따른 핸디캡이 분명 있나봐요..
그래도 영어 공부는 언제나 즐겁습니다. 모국어였다면 이런 즐거움은 몰랐겠지요..
제 글에 친절하게 설명해주셔서 감사드립니다.

jeongheumjo의 이미지

제가 잘못썼는데 수정이 안되는 것 같아서 답글로 밝힙니다.
export "C"
라고 쓴 부분들은 오자이고요
extern "C"
입니다.

그리고 해당 글 '공유 라이브러리를 만들 때는 꼭 C 모듈만을 위하지는 않지 않나요?' 에서는 다른 부분도 오류 투성이네요.. 모르고 말을 하면 이렇게 헛말을 하게 되나봅니다... 마지막 결론 부분을 참고해주세요..

Anti-Lock의 이미지

표준에 관한건 잘 모르지만,
"extern 이 없으면 기본적으로 변수는 모듈(.cpp 파일) 안에서만 참조할 수 있는 internal linkage 를 갖게 되고,"
이 말은 좀 사실관계가 다른것 같은데요.. 해당 키워드는 static 아닌가요?
또한 extern 키워드가 없더라도 다른 cpp 파일에서 참조 할 수 있습니다.
static선언을 하지 않은이상 해당 심벌은 공개?되고 외부 모듈에서 참조 될 수 있습니다.
편법인가 아닌가 하는 문제는 있을 수 있겠습니다만, 링커입장에서는 편법이 아닐겁니다.

그리고 cpp에서 extern "C"키워드가 없더라도 c에서네임 맹글링된 함수를 호출할 수 있을 겁니다.
해당 심벌이 있으면 링커가 연결해주겠지요.
런타임 실행을 보장할려면, ABI가 문제없는지 확인은 필요할겁니다.

cleol의 이미지

아, 착각했네요. 말씀하신대로 "변수"는 기본적으로 external 입니다. "const 심볼"인 경우에 기본적으로 internal 이구요.

> 그리고 cpp에서 extern "C"키워드가 없더라도 c에서네임 맹글링된 함수를 호출할 수 있을 겁니다.

C 모듈에서 명시적으로 name mangling 된 형태로 호출하지 않는 이상, 찾는 이름이 다르기 때문에 찾지 못할겁니다.
컴파일러 구현에 따라 다르기는 하겠지만, gcc 에서 한번 테스트를 해봐야겠네요.

Anti-Lock의 이미지

저도 좀 헷갈리게 적어놨네요..
"cpp에서 맹글링된 이름"을 알면 C 에서 "그 이상한 이름을 써서"찾을수 있다는 이야기입니다.
물론 그이름이 컴파일러 제작사마다, 버전마다 달라질수 있겠지만요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.