[완료] 초기화하지 않은 전역 변수의 중복 문제

nondie의 이미지

두개의 파일에 선언된 전역변수가 이름이 같아서 문제가 된 적이 있습니다.
변수명이 같을 경우 당연히 컴파일 타임에 에러가 발생할 거라고 생각해왔는데
그렇지 않아서 상당히 놀랐습니다.
그래서 간단한 코드로 확인해 본 결과 상당히 재미있는 결과가 나왔습니다.

시험 방법은, 두개의 c파일에 동일한 이름의 변수를 넣고 또다른 c 파일에서
해당 변수를 접근하는 식으로 했습니다.

1. 변수를 초기화 할 경우 :
1) 중복 에러 발생
2) nm 출력 결과 : 00000000 D var

2. 변수를 초기화 하지 않을 경우 :
1) 중복 에러 발생하지 않음
2) nm 출력 결과 : 00000004 C var

3. 변수를 한군데만 초기화 한 경우 :
1) 중복 에러 발생하지 않음

결국 초기화를 해서 타입이 C 인 변수가 두군데 이상 같은 이름으로 존재하면
중복이고 그렇지 않으면 중복이 아닌 것으로 링커에서 처리하는 것 같은데
D와 C의 차이, 그리고 링킹 메커니즘에 관해서 간단하게 설명해 주실 수 있나요?

coderheart의 이미지

C 언어에 대해 질문하신 것 같으니 우선 C 부터 설명드리겠습니다.
본래 전역 변수라는 것을 다른 소스 파일에서 정의된 것을
사용하려 할 때, extern int c; 와 같이 extern 으로 선언을 해야 원칙입니다.
그렇지 않으면 이 것은 외부 전역 변수와 충돌되는 것입니다.
하지만, 우리의 상식과는 달리 에러를 내보내지 않습니다.
이는 마치
외부 함수 선언부에서는 extern 을 생략해도 되고,
외부 변수 선언부에서는 extern 을 해야한다는 원칙에 위배되는 듯 합니다.

그럼 본격적으로 질문에 대한 답을 드리겠습니다.
왜 초기화를 두군데에서 할 때만 에러를 내는가.
본래 컴파일러는 원칙에 충실해야 하지만, C 의 메카니즘이 복잡하다 보니 초보 개발자들을 위한 배려가 존재합니다.
컴파일러가 개발자에게 하는 배려 중 하나는, 많이 알려진 타입 유추입니다.
기본적으로 C 컴파일러는 타입유추 기능은 거의 없습니다. 다만 타입 암시적 변환를 에러없이 처리한다는 것이죠.
하지만 C++ 및 대다수의 함수형 언어는 타입 유추가 존재합니다.
타입을 명시적으로 쓰지 않더라도 사용자 소스 코드를 분석하여 타입을 유추합니다.
(사실 C++ 함수형 언어와 달리 완벽한 타입유추는 아닙니다. 일반적으로는 템플릿 인자에 대해서만 유추가 가능합니다.)

하지만 여기서 언급되어야 할 것은 타입유추가 아닌 코드유추입니다.
비록, extern 이 없더라도 초기화가 된 변수를 실제 변수가 정의된 부분이라 보고,
초기화가 이루어지지 않은 부분의 변수를 extern 선언된 부분이라 유추하는 것입니다.

하지만 두개 모두 초기화를 하게 되면, 어느 것도 extern 선언된 부분이 존재하지 않는 것이며,
둘 다 전역에 실존하는 변수라는 말이 되버립니다.
하지만, 같은 네임스페이스에 변수명이 동일하다는 것은 모순입니다.
따라서 에러를 발생합니다.

요약하자면, 오직 전역에 변수는 하나만이 실존합니다. 나머지는 코드 유추에 의해서 extern 선언으로 가정됩니다.

그렇다면, 의문이 생길텐데요. 모두 초기화를 하지 않은 경우는?
이 경우 a.c 이나 b.c 둘 중 아무데나 정의, 선언을 하던지 아무런 상관이 없기 때문에
컴파일러/링커 재량에 의해 해결됩니다.
오히려 컴파일러의 배려가 때로는 개발자에게 혼란을 주는 부분이라 할 수 있겠습니다.

이상입니다 ^^;

이 질문에서 컴파일러/링커에 대한 자세한 논의까지는 필요없을 것 같아 생략했습니다.
도움이 되신다면 좋겠습니다.

------

추가로 C++ 은 C 언어와 달리 강한 타입 / 코드 체킹을 요구합니다.
extern 키워드는 필수입니다. C++ 로 컴파일 하신다면, 둘 중 하나는 반드시 extern 으로 해야하는 것을
아실 수 있을 것입니다.

nondie의 이미지

결국 원래 알고 있던대로 중복이 발생하는게 맞고 그렇지 않은 경우는
컴파일러나 링커의 재량에 따른 배려에 의해서 그렇다는 얘기군요.
그것때문에 컴파일타임이 아닌 런타임에 에러가 발생해서 고생한 걸
생각하면 별로 고맙지 않은 배려내요. ^^

역시 C++처럼 strong type checking을 하는 편이 오히려 런타임의
에러 가능성을 줄일 수 있어서 좋군요.

댓글 달기

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