C 매크로 함수의 return값 지정을 어떻게 하나요?

ixevexi의 이미지

보통
#define MAX(a,b) ( (a>b) ? (a) : (b) )

이런식으로 매크로 함수를 정의합니다.
하지만 약간 복잡한 형태의 함수의 return값을 명시적으로 주고자 했을때 어떻게 해야합니까?

#define func(a) {\

//bla~ bla~ bla; \

/*return*/ result;
}

이렇게 하게되면 {}로 둘러쌓인 부분이 result로 평가 받게 되나요?

혹은 그렇지 않다면 어떻게 해야합니까?

sangwoo의 이미지

조금 복잡하다면 함수로 만드는 게 옳은 방법이겠지요. :-)
오버헤드가 염려된다면 함수에다 __inline지시자를 주는 방법이 있겠습니다. 단, __inline은 컴파일러에게는 권고사항일 뿐이고, 반드시 지켜지는 것은 아닙니다.

----
Let's shut up and code.

ixevexi의 이미지

inline으로 변화가 없어서 할려는 것이고
게다가 조금복잡한게 아니라 단순히 return값만 불리는 거라서 그렇습니다

C++, 그리고 C++....
죽어도 C++

wariua의 이미지

#define func(a) ({\ 

//bla~ bla~ bla; \ 

/*return*/ result; \
}) 

요런식으로 하면 result가 ({ blahblah...; result; }) 표현의 평가값이 되니까

ret = func(something);

식으로 사용할 수는 있을 것 같습니다만, 아무래도 이건 좀...-.-a

$PWD `date`

ixevexi의 이미지

제가 궁금하던것이 바로 그것입니다.
과연 { ~~~~~; ~~~~; result;}의 평가값이 result가 되는냐는 것이죠

문법적으로 옳은것인가요?

C++, 그리고 C++....
죽어도 C++

wariua의 이미지

http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

GCC extension이라는 걸로 봐서 표준은 아닌 듯 합니다. -pedantic 옵션으로 컴파일 하니까 뭐라뭐라 그러네요. 하지만 다음과 같이 정의하는 건 표준 C 문법에 부합합니다.

#define func(a) ( \
    tmp1 = another_func1(a), \
    tmp2 = another_func2(a), \
    result = tmp1 + tmp2, \
    /* return */ result )

...
int tmp1, tmp2, result;  // for use by macro func()
...
ret = func(a);

즉, 선언'문' 없이, '식'으로만 이뤄져 있으면 GCC뿐 아니라 모든 ANSI C 컴파일러에서 문제가 없게 됩니다... 만, 원하시는 것에는 이프로 부족하지 않을까 싶네요-

$PWD `date`

M.W.Park의 이미지

매크로는 확장(expansion)될 뿐 그 이상도 이하도 아닙니다.
소스에 그대로 대치되는 것입니다.
실제로 전처리기가 매크로를 다 풀어헤친(?) 상태의 소스를 컴파일하게 됩니다.
매크로의 리턴 값이라고 하면 말이 앞뒤가 안맞는 느낌이 드네요.

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

익명 사용자의 이미지

M.W.Park wrote:
매크로는 확장(expansion)될 뿐 그 이상도 이하도 아닙니다.
소스에 그대로 대치되는 것입니다.
실제로 전처리기가 매크로를 다 풀어헤친(?) 상태의 소스를 컴파일하게 됩니다.
매크로의 리턴 값이라고 하면 말이 앞뒤가 안맞는 느낌이 드네요.

동의합니다. 8)

매크로에서의 리턴값이란거부터가 이미 말이 안되는거죠.
스스로 pre-processor입장이 되어서 매크로가 삽입되는 과정을
시뮬레이션 해보시면 잘 이해할 수 있을겁니다.

그럼 매크로에서 return 문을 쓰게 되었을 때 매크로가 값을
리턴하는게 아니라 매크로가 삽입된 함수가 값을 리턴하며
끝나게 된다
는것도 이해가 가실줄로 압니다.

익명 사용자의 이미지

ixevexi wrote:
제가 궁금하던것이 바로 그것입니다.
과연 { ~~~~~; ~~~~; result;}의 평가값이 result가 되는냐는 것이죠

문법적으로 옳은것인가요?

statement가 세개니까 각각 독립적으로 세번 평가 되겠네요.
그렇겠죠?

cinsk의 이미지

몇가지 정리하면 다음과 같습니다.

첫째, 표준에 따라, statement를 expression이라고 할 수 없습니다. 물론 statement의 정의에 따라, expression-statement가 될 수 있기는 하지만, 모든 statement가 expression이라고 할 수 없습니다. 따라서

Quote:

과연 { ~~~~~; ~~~~; result;}의 평가값이 result가 되는냐는 것이죠

는, 표준에 따라 잘못된 질문입니다.

둘째, 복잡한? 매크로를 만들고 싶다면 inline function을 쓰기 바랍니다. inline function을 쓰는 것이 여러모로 편리하고, 안전합니다. 다음과 같이 쓰면 좋습니다:

static inline void
foo(void)
{
  ...
}

세째, gcc C 언어 확장 기능으로, (즉, 표준이 아니며, 다른 컴파일러에서 지원하지 않는..) compound statement (중괄호로 둘러싼 여러 statement)를 expression으로 해석하는 기능이 있습니다. 예를 들면:

({ int y = foo(); int z;
    if (y > 0) z = y;
    else z = - y;
    z; })

로 쓴 것처럼, foo() 리턴 값의 절대값을 얻는 코드를 위와 같이 작성할 수 있습니다. 이 것은 C99 표준에서 inline function이 나오기 전에 매우 유용하게 썼던 기능입니다. expression에서 switch, for 등의 statement를 쓸 수 있는 등의 장점을 얻을 수 있었습니다. 실제로 GNU C library에 포함되어 있는 obstack에 관계된 대부분의 함수가 이 compound-statement expression을 써서 macro로 구현되어 있습니다. 물론 맨 마지막 statement의 값이, 이 compound statement의 값이 됩니다.

그런데, 이 기능은 현재 C++에서 쓸 경우, 임시 변수의 destructor가 불리는 순서가 바뀌는 등의 단점이 있기 때문에, C++로 쓸 우려가 있는 코드에서는 이 compound statement expression을 쓰지 말라고 권하고 있습니다.

개인적으로 간단한 수식으로 나올 수 있는 것이 아니라면 do { ... } while (0)을 써서 macro로 만들고, 어떤 값을 리턴할 필요가 있는 macro라면 inline function을 쓰는 것이 좋다고 생각합니다.

익명 사용자의 이미지

매크로 함수 기능은 대단히 주의깊게 이용되어야만 합니다.

http://groups.google.co.kr/group/comp.os.linux/browse_frm/thread/9690464b197bcb79

#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)

아무 문제 없을것 같은 코드지만

-------------------bug.c-------------------------
#include <linux/ctype.h>
main()
{
printf("%d\n", toupper('x') == toupper('y'));
printf("%d\n", toupper('x') == toupper('X'));
}
-------------------------------------------------

he program below prints:
1
1
but should print:
0
1

ixevexi의 이미지

M.W.Park wrote:
매크로는 확장(expansion)될 뿐 그 이상도 이하도 아닙니다.
소스에 그대로 대치되는 것입니다.
실제로 전처리기가 매크로를 다 풀어헤친(?) 상태의 소스를 컴파일하게 됩니다.
매크로의 리턴 값이라고 하면 말이 앞뒤가 안맞는 느낌이 드네요.

NN_2 wrote:

동의합니다.

매크로에서의 리턴값이란거부터가 이미 말이 안되는거죠.
스스로 pre-processor입장이 되어서 매크로가 삽입되는 과정을
시뮬레이션 해보시면 잘 이해할 수 있을겁니다.

그럼 매크로에서 return 문을 쓰게 되었을 때 매크로가 값을
리턴하는게 아니라 매크로가 삽입된 함수가 값을 리턴하며
끝나게 된다는것도 이해가 가실줄로 압니다.

제가 쓴 글을 잘 읽어보세요 ^^ 오해하신것 같습니다.
매크로 함수의 return값은 말이 안되는것이 맞습니다만
a = func(); 와 같은 효과를 내기위해 물어본 것이었습니다.
저도 매크로 함수의 return값이 이상하다는 건 잘 알고 있습니다.

결론적으로 gcc extension을 사용하는 방법 이외에는 없네요
(gcc가 inline을 강제 하게 할 수 있는 방법을 찾지 않는이상)
원래 저도 표준의 inline을 썼다가 별 차이를 못느껴서
(inline이 적용이 되었나 안되었나를 모르겠더라구요^^)
macro함수를 쓰려던 것이었습니다.

저는 C++를 좋아하고 그렇기에 C스타일인 매크로 쓰는걸
별로 내켜하지 않습니다 ㅠ.ㅠ

C++, 그리고 C++....
죽어도 C++

sangwoo의 이미지

매크로와 함수는 각각 할 일이 있는 거라고 봅니다. 함수 호출의 오버헤드가 아주 중요한 요인으로 작용하는 경우가 아니라면, 함수를 쓰는 것이 맞다고 생각하구요. (그리고 그런 경우는 별로 없더군요..)

말씀하신 상황에서 굳이 매크로를 쓰고 싶으시다면 SOME_MACRO(input, output) 처럼 매크로를 정의해서 argument 에 바로 값을 넣도록 만드는 것이 옳은 방법이라고 생각합니다.

----
Let's shut up and code.

댓글 달기

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