#define 사용 시 멤버 변수를 for문 인자로으로 받을 수 없나요?

ponicon3의 이미지

다음과 같은 코드는 정상 동작 합니다.
#if 1
#define INT_i(n) int i##n = n;
#define SUM(res, n) (res) += i##n
#define PRINT(n) printf("i%d = %d\n", n , i##n)

int main()
{
int res=0;
int i;

for(i=0; i<2; i++)
{
INT_i(i);
PRINT(i);
SUM(res,i);
}

printf("결과 : %d\n", res);

return 0;
}
#endif

**실행결과**
i0 = 0
i1 = 1
결과 : 1

다음과 같은 코드는 컴파일 에러가 납니다.
#if 1
#define INT_i(n) int i##n = n;
#define SUM(res, n) (res) += i##n
#define PRINT(n) printf("i%d = %d\n", n , i##n)

int main()
{
int res=0;
int i;
#if 1
int i0, i1,i2;
i0 = 0;
i1 = 1;
#endif

for(i=0; i<2; i++)
{
/* INT_i(i); */
PRINT(i);
SUM(res,i);
}

printf("결과 : %d\n", res);

return 0;
}
#endif

**컴파일결과**
a.c: In function 'main':
a.c:61: error: 'ii' undeclared (first use in this function)
a.c:61: error: (Each undeclared identifier is reported only once
a.c:61: error: for each function it appears in.)

첫번째 코드와 다르게 i0, i1 을 직접 선언하는 경우
#define 매크로에서 ##으로 연결하는 부분을 넘겨받는 숫자가 아니라 문자 그대로 i로
인식을 하는데요.. 변수를 선언하고 쓰는 것과 for에서 INT_i(i) 로 선언해서 쓰는 것이
왜 결과가 다를까요?
구조체 멤버를 i0, i1, i2 형태로 해서 for문을 돌려서 사용 하고 싶은데
위 예제와 똑같은 에러가 나네요.. 어떻게 사용할 방법이 없을까요?

shint의 이미지

[Error] 'ii' was not declared in this scope

ii 라고 이름이 나옵니다.

//
이런 방식인거 같습니다.

#define FN(n) n
#define FN2(n) n
 
 
#if 1
#define INT_i(n) int i##n = n;
#define SUM(res, n) (res) += n;
#define PRINT(n) printf("i%d = %s %d\n", n, #n, FN(n));
#define PRINT2(n) printf("i%d = %s %d\n", FN2(i0), #n, FN(n));
 
 
//n     변수
//##n   변수
//#n    문자
//FN(n) 숫자
 
 
//[Error] 'ii' was not declared in this scope
 
int main()
{
    int res=22;
    int i;
 
    #if 1
    int i0=11;
    int i1=1;
    int i2=2;
    #endif
 
    for(i=0; i<2; i++)
    {
        //INT_i(i);
        char buf[2];
        buf[0] = '\0';
        buf[1] = '\0';
        sprintf(buf, "%d", i);
        printf("%s\n", FN(buf));
 
        SUM(res,i);
        PRINT(i);
    }
    printf("결과 : %d\n", res);
 
    return 0;
}
#endif
 
 
#if 0
0
i0 = i 0
1
i1 = i 1
결과 : 23
#endif

#define ##arg 이런 내용도 있네요.
http://www.google.co.kr/search?q=%23define+%23%23arg&hl=ko&biw=&bih=&gbv=2&oq=%23define+%23%23arg&gs_l=heirloom-serp.3..0j0i30l9.639.3995.0.4386.5.5.0.0.0.0.250.866.1j2j2.5.0....0...1ac.1.34.heirloom-serp..1.4.615.8YY-CdZpY5Y

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

익명 사용자의 이미지

C언어를 사용하실 때는, 프로그램을 컴파일하고 실행하는 과정에서 다음과 같은 4단계를 거친다는 것을 확인하고, 자신이 원하는 작업이 어느 단계에서 이루어지길 바라는지 분명히 할 필요가 있습니다.

[전처리 단계] -> [컴파일 단계] -> [링크 단계] -> [실행(런타임) 단계]

질문자님이 제시하신 첫 번째 코드는 분명히 잘 컴파일되고 (아마도) 의도하신 대로 실행되는 것처럼 보이지만 전혀 그렇지 않습니다. 매크로 확장 결과 어떻게 되는지 보여드리죠.

int main()
{
int res=0;
int i;

for(i=0; i<2; i++)
{
int ii = i;; // INT_i(i)
printf("i%d = %d\n", i , ii); // PRINT(i)
(res) += ii; // SUM(res, i)
}

printf("결과 : %d\n", res);

return 0;
}

보이십니까? for문 안에서 i=0일 때 INT_i(i)가 int i0 = 0; 이 되길 바라신 것 같은데, 틀리셨습니다.
매크로 확장은 전처리 단계에서 일어납니다. 전처리기는 for문이 뭔지도 모르고, 심지어 i가 변수인지 아닌지도 모릅니다.
전처리기가 아는 건 그냥 n 자리에 문자열 i가 들어왔다는 것 뿐이고, int i##n = n;에 고스란히 치환해서 int ii = i;으로 만들 뿐입니다.
그 아래의 다른 매크로들도 마찬가지입니다. 분명히 의도한 것과 다른데 우연히도 맞는 코드가 만들어져서 잘 도는군요. 이럴 때 참 골치 아프죠.

이 점을 상기하면 둘째 코드가 왜 컴파일이 안 되는지도 아시겠지요.

int main()
{
int res=0;
int i;
int i0, i1,i2;
i0 = 0;
i1 = 1;

for(i=0; i<2; i++)
{

printf("i%d = %d\n", i , ii); // PRINT(i)
(res) += ii; // SUM(res, i)
}

printf("결과 : %d\n", res);

return 0;
}

변수 ii는 애초에 선언되지도 않았으니 컴파일이 안 되는 게 당연하지요.

구조체 멤버를 i0, i1, i2 와 같이 만들어서 for문을 돌려서 사용하고 싶으시다고요?
for문은 실행 단계에서 동작하는 겁니다. 그러면 (전처리 단계가 아니라) 실행 단계에서 참조할 수 있게 짜야죠.
가장 편한 방법은 배열입니다. 아래와 같은 코드는 어떤가요.

#include

struct foo{
int i[2];
};

int main(void){
struct foo bar;
int i, res=0;

bar.i[0] = 0;
bar.i[1] = 1;

for(i=0;i<2;i++){
printf("bar.i[%d] = %d\n", i, bar.i[i]);
res += bar.i[i];
}

printf("결과 : %d\n", res);
return 0;
}

한편 배열의 크기는 컴파일 단계에서 정해져 있어야 하니, 그것까지 실행 단계에서 지정하려면 동적 할당을 써야 합니다.

#include
#include

struct foo{
int *i;
};

int main(void){
struct foo bar;
int i, res=0;
int n;

if(scanf("%d", &n) != 1 || n <= 0)
return EXIT_FAILURE;

bar.i = (int *)malloc(n * sizeof(int));
if(!bar.i)
return EXIT_FAILURE;

for(i=0;i bar.i[i] = i;
}

for(i=0;i printf("bar.i[%d] = %d\n", i, bar.i[i]);
res += bar.i[i];
}

printf("결과 : %d\n", res);
free(bar.i);
return 0;
}

마지막으로 덧붙이자면, 매크로 함수 쓰기 전에는 꼭 한번 더 생각하세요. 특히 ##와 같이 쓸 때는 더더욱.

익명 사용자의 이미지

레이아웃이 이상하게 깨졌네요. printf문 안에 들어간 특수문자 때문인 것 같은데 읽는 데는 문제 없으리라고 생각됩니다. 그 바로 밑에 드린 코드의 printf문이랑 똑같아요.

댓글 달기

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