헤더에 변수 선언에 대해 여쭤볼 것이 있습니다.

hoochoona의 이미지

헤더가 중복포함 되지 않기 위해 방지하는 것이 include guard가 있지 않습니까?
헌데 여기서 의문점인것이 include guard가 적용된 헤더안에서 변수를 선언 하게되면 에러가 발생하는데, ODR에 어긋나게 되어 에러가 발생하게 되는것 같습니다.

더 자세하게 이야기를 풀어보면...

//test.h
#ifndef _TEST_H_
#define _TEST_H_
 
int g_i = 0;
 
#endif // _TEST_H_

위와 같은 test.h 라는 헤더파일이 존재 합니다. #ifndef ~ #endif 사이는 한번 읽히게 되면 _TEST_H_ 가 정의되기에 그 다음 부터는 읽혀지면 아니되는것으로 알고 있었습니다만...
이상하게도 g_i 는 ODR(One Definition Rule)에 어긋나게되어 에러가 발생되는 것 같습니다. 어차피 한번 읽힐테니 한번 선언 될텐데 말입니다.

그런데 여기서

//test.h
#ifndef _TEST_H_
#define _TEST_H_
 
int g_i;
 
#endif // _TEST_H_

g_i 에 값을 초기화 하지 않은 전역변수라면 문제없이 한번 선언이 되어 ODR에 어긋나지 않아 에러가 발생되지 않습니다.

왜 그런지 알 수 있을까요?

해답을 알고싶습니다.

ymir의 이미지

storage class 가 명시되지 않으면 extern 이 생략된 것과 같이 취급되니..
앞에 extern 을 붙여 보면.. 두 번째 것이 전혀 문제가 없다는 건 금방 이해가 가실테고..

첫 번째 것은 external linkage 를 갖는 녀석을 초기화 하려하니, 중복 선언 에러가 나는 거죠..
앞에 static 을 붙여서 internal linkage 로 바꿔주면 문법상 전혀 문제가 없습니다.
다만, 원래의 의도가 external linkage 를 원한 것이라면..
두 번째 처럼 선언만 하고, 초기화는 프로그램 내에서 별도로 하셔야 합니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

HDNua의 이미지

1. 저장소 지정자가 명시되지 않으면 기본으로 extern인가요?

int num; // 전역 변수를 정의하는 부분인데, extern int num과 같습니까? auto일줄 알았는데요..
int main() {
 num = 0;
 return 0;
}

함수는 기본적으로 extern으로 된다는 건 알고 있었습니다만 모든 선언에 대해 맞는지 궁금합니다.
아니면 변수와 함수 간에 기본 저장소 지정자가 다르게 정의되어있는지?

저는 이렇게 생각했습니다.

ymir의 이미지

> storage class 가 명시되지 않으면 extern 이 생략된 것과 같이 취급되니..
> 앞에 extern 을 붙여 보면.. 두 번째 것이 전혀 문제가 없다는 건 금방 이해가 가실테고..

아뇨.. global variable 은 default 가 extern 도 아니고 static 도 아니라서..
extern 을 명시적으로 붙인 것과는 다른데.. 제가 착각하고 설명을 전혀 엉뚱하게 했습니다.
보통은 실제 모듈 안에 심볼을 정의하고, 헤더에 extern 을 넣는다는 얘기를 한다는게.. 뭔가 빼먹고 이상한 결론만 넣었네요.
이해하고 계신게 맞고, 추가로 아래 jick 님이 올리신 링크 참조하시면 더 도움이 될겁니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

hoochoona의 이미지

일하다가, 갑자기 정말 문뜩 떠올랐던 생각이였습니다.
include guard 가 적용 되어있는 헤더가 변수 중복 선언 에러가 발생하게 되는 원리가 뭘까 라는 생각이 번뜩였습니다.
찾아보고는 있지만 여전히 해답을 알 수가 없어서 살짝 묘하네요...

헤더안에서 앞에 키워드가 안붙은 변수선언은 하지 않는 편입니다만.
질문글에서 말씀드렸던것과 같이 include guard가 적용되어있음에도 불구하고 변수 선언 라인을 두번 이상을 읽는 다는 점이 여전히 모르겠군요~

내부적으로 #ifndef ~ #endif 조건이 맞지 않아도 컴파일러가 읽는 것도 아니지 말입니다.

-----------------------------
안녕하세요. 후추나입니다.
http://blog.naver.com/chhh92
...
실패는 좋은 경험치.

jick의 이미지

여기의 첫번째 답변에 설명이 잘 되어 있는 것 같습니다.

http://stackoverflow.com/questions/3691835/why-uninitialized-global-variable-is-weak-symbol

hoochoona의 이미지

정보 감사합니다. :)

-----------------------------
안녕하세요. 후추나입니다.
http://blog.naver.com/chhh92
...
실패는 좋은 경험치.

댓글 달기

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