전역변수 사용및 header file 선언하는 방법을 알고 싶습니다.

blackash의 이미지

gcc 에서와 g++ 에서의 전역변수를 어떻게 선언해 주어야 하는지 궁금해서 글을 올립니다.

header 파일 하나에 전역변수를 모두 집어 넣고 컴파일을 하려고 했었는데 안됩니다. 여러군데 헤매고 다녀도 정확한 답변을 찾을수가 없어서 글을 올립니다.

---------test.h--------------

#ifndef __TEST__
#define __TEST__

#include <stdlib.h>
#include <stdio.h>

double test;
void temp();

#endif

================================

---------test.c---------------

#include "test.h"


int main(int argc, char* argv[])
{
  test = 7.0;

  temp();
  printf("%f\n",test);

  return 0;
}

=================================

----------temp.c----------------

#include "test.h"


void temp()
{
        test = 9.0;
        printf("%f\n",test);
} 

=====================================

------------ 출력물 -----------------------

[root@horse test1]# gcc -Wall -o temp test.c temp.c 
[root@horse test1]# ./temp 
9.000000
9.000000
[root@horse test1]# g++ -Wall -o temp test.c temp.c 
/tmp/ccsH9ubr.o(.bss+0x0): multiple definition of `test'
/tmp/cckCtSro.o(.bss+0x0): first defined here
collect2: ld returned 1 exit status
[root@horse test1]# 

========================================

처음에는 source 파일을 cpp 라는 확장자를 붙여 놓고 컴파일했었는데 그렇게 하면 컴파일이 안되더군요.

질문 1. gcc 로 컴파일을 하더라도 cpp 라는 확장자를 가지고 있으면 g++ 로 컴파일을 하는것인지 궁금합니다.

질문 2. c++ 에서 전역변수를 헤더 파일 하나에 선언할수 있는 방법을 알고 싶습니다.

wongi의 이미지

Quote:
질문 1. gcc 로 컴파일을 하더라도 cpp 라는 확장자를 가지고 있으면 g++ 로 컴파일을 하는것인지 궁금합니다.

제가 작업하는 시스템에는 gcc version 2.96 가 설치되어 있습니다.
man page에 따르면 C/C++ 컴파일러가 통합되었으며, 호출하는 이름에 기본 가정만이 달라진다고 합니다. man gcc... :)

Quote:
질문 2. c++ 에서 전역변수를 헤더 파일 하나에 선언할수 있는 방법을 알고 싶습니다.

전역 변수를 사용하는 모든 파일에서 해당 변수를 "선언"해야 하지만, "정의"는 하나의 파일에서만 이루어져야 합니다.
pure-ftpd에서 다음과 같은 트릭(?)을 발견하였습니다.

#ifdef DEFINE_GLOBALS
# define GLOBAL0(A) A
# define GLOBAL(A, B) A = B
#else
# define GLOBAL0(A) extern A
# define GLOBAL(A, B) extern A
#endif

globals.h에 위와 같은 매크로를 정의하고, main이 되는 파일에서만 DEFINE_GLOBALS를 define한 뒤에 include합니다.

KISS...
Keep It Small and Simple

pastime의 이미지

전에 어떤 책에서 본 내용이 생각나 적어봅니다.

우선 헤더 파일을 다음과 같이 작성합니다.
----------------- test.h -------------------

#ifndef __TEST__ 
#define __TEST__ 

#include <stdlib.h> 
#include <stdio.h> 

#ifdef EXT_GLOBAL
#define EXT 
#else
#define EXT extern
#endif

// 이 부분!!
EXT double test; 

void temp(); 

#endif

그리고 이 변수를 처음 선언하는 한 곳에서만

"test.h" 를 include 하기 전에

EXT_GLOBAL 을 define 해 주면 됩니다.

----------------- test.c -------------------

#define EXT_GLOBAL
#include "test.h" 

/* 이하 생략 */

----------------- temp.c -------------------

#include "test.h"

/* 변화 없음 */
M.W.Park의 이미지

일반적으로 헤더에선 선언(declaration)만 하는 것이 좋습니다.
정의(definition)을 하게 되면 문제가 될 경우가 많습니다.
즉 선언은 소스코드의 여러부분에 나와도 되지만, 정의는 단 한번만 나와야하는 것입니다.

헤더에선 전역변수를 extern으로 잡고, test.c 또는 temp.c 에서 변수를 정의 하시는 것이 좋을 것같네요.

-----
오늘 의 취미는 끝없는, 끝없는 인내다. 1973 法頂

morison77의 이미지

제가 아는 바에 의하면 헤더에 extern으로 선언된것은
소스 어디선가 정의해야 하는 걸로 알고 있는데

언젠가 헤더엔 extern 해놓고 그 헤더를 include 하는 어느 소스에서도
그 변수를 정의해주지 않았는데
-Wall 옵션을 주고 컴파일을 해도 컴파일이 되더군요
제가 알기론 extern되어 있는 변수는 분명히 어디선가 정의 되야
하는 걸로 알고 있는데 제가 잘못 알고 있는건지요?

light my fire

옥정훈의 이미지

a.c 에는
int variable;
로 정의하고

a.h 에는
extern int variable;
선언한 후

저 전역변수를 사용하고 싶으면
#include "a.h"

하면 됩니다.

전웅의 이미지

morison77 wrote:
제가 아는 바에 의하면 헤더에 extern으로 선언된것은
소스 어디선가 정의해야 하는 걸로 알고 있는데

언젠가 헤더엔 extern 해놓고 그 헤더를 include 하는 어느 소스에서도
그 변수를 정의해주지 않았는데
-Wall 옵션을 주고 컴파일을 해도 컴파일이 되더군요
제가 알기론 extern되어 있는 변수는 분명히 어디선가 정의 되야
하는 걸로 알고 있는데 제가 잘못 알고 있는건지요?

C 언어의 외부 정의 모델은 기본적으로 초기치 모델 (initializer model)
에 기반합니다. 따라서, 외부 연결 명칭을 갖는 대상체의 선언에 모두
extern 이 있다고 해도, 그 중 하나라도 초기치가 명시적으로 주어지는
경우에는 정의로 취급됩니다:

[mycoboco@nas01 mycoboco]$ cat t.c
extern int i = 0;

int main(void)
{
    return i;
}

[mycoboco@nas01 mycoboco]$ cat t2.c
extern int i;

[mycoboco@nas01 mycoboco]$ gcc -ansi -pedantic -W -Wall t.c t2.c
t.c:1: warning: `i' initialized and declared `extern'

여기서 발생하는 경고는 프로그램이 잘못 되었기 때문이 아니라 순전히
infomative 의 성격을 갖습니다.

또 다른 가능성으로는 해당 명칭이 sizeof 연산자를 제외한 수식에서 아
예 사용되지 않는 경우입니다. 대상체 명칭이 외부 연결인 경우, 수식에
서 사용되지 않거나 sizeof 연산자의 피연산자로만 사용되는 경우 정의가
제공되지 않아도 상관 없습니다:

[mycoboco@nas01 mycoboco]$ cat t.c
extern int i;

int main(void)
{
    return sizeof i;
}

[mycoboco@nas01 mycoboco]$ cat t2.c
extern int i;

[mycoboco@nas01 mycoboco]$ gcc -ansi -pedantic -W -Wall t.c t2.c

물론, 정의가 제공되지 않고 모든 선언이 초기치 없이 extern 으로 선언
된다면 정의가 제공되지 않는 것이므로 잘못된 것입니다:

[mycoboco@nas01 mycoboco]$ cat t.c
extern int i;

int main(void)
{
    return i;
}

[mycoboco@nas01 mycoboco]$ cat t2.c
extern int i;

[mycoboco@nas01 mycoboco]$ gcc -ansi -pedantic -W -Wall t.c t2.c
/tmp/ccTkjj2H.o: In function `main':
/tmp/ccTkjj2H.o(.text+0x5): undefined reference to `i'
collect2: ld returned 1 exit status

참고로, block scope 의 명칭 선언이 extern 과 초기치를 모두 갖는 것
은 허락되지 않습니다 - 따라서, block scope 의 선언이 (순수한 선언이
아닌) 외부 정의로 해석될 가능성은 배제됩니다.

(IT 백두대간 C 언어, pp.908-915)

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

댓글 달기

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