C에서 Magic Number(상수, 배열의 크기등)을 선언시 어떻게 하시

dgsquare의 이미지

저는 주로 Magic Number를 정의할때,
#define MAXROW 80
뭐 이런식으로 사용하였습니다.

그런데 The Practice of Programming을 읽다보니,
enum {
MAXROW = 24,
MAXCOL = 80,
...
}
이런식으로 사용하라고 추천하는 군요.

개인적으로 상수는 거의 #define을 사용하였습니다. enum형은 특정 type의 symbol이나, flag등을 정의할때만 사용했구여...
실제 Kernel소스에서도 #define구문으로 상수 정의를 해놓지 않나여? 그런걸로 기억나는데....


책에 나온 간단한 설명은 다음과 같은데, 정확한 의미를 모르겠네여.

Quote:
C programmers have traditionally used #define to manage magic number values. The C preprocessor is a powerful but blunt tool, however, and macros are a dangerous way to program because they change the lexical structure of the program underfoot.

아-! 그리고 상수를 매크로로 선언시, 어떤 문제가 발생할수 있는지, 아시는 분의 조언 부탁드립니다. :)

서지훈의 이미지

저 같은 경우 상수는 최대한 const를 이용해서 사용을 할려 합니다.
#define의 경우 잘 못 사용된 경우에도 에러 체킹이 어려운 반면 const를 이용하게 되면은 타입이 있는 일반 상수 이기 때문에 좀 더 안전하게 사용이 가능할 것입니다.
근데... 속직히 실제 프로그래밍에는 큰 차이는 없겠지만 혹시나 있을지 모르는 에러를 막자는 취지 이지 잘만 사용하면 편합니다.
이의 사용은...
if ( a == 0) OR if (0 == a)
정도의 사용으로 보면 되지 않을지 ...
위 코드는 하는 일은 같지만 후자쪽이 확실히 안전합니다.

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

ctcquatre의 이미지

흠... 왜 후자쪽이 안전한가요?

안전이 가리키는걸 잘 모르겠네요.

설명 부탁드립니다.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

Fe.head의 이미지

추측하건데

if(a == 0)

를 실수로

if(a = 0)

게 되면 컴파일러가 에러를 잡지 못하지만

if(0 = a)

는 컴파일러가 잡을수 있을것 같은데요

맞나요?

좋은걸 배웠습니다. 서지훈님 감사 :D

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

ctcquatre의 이미지

아.. 그런건가요?

정말 그럴수도 있겠네요.

좋은 팁입니다.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

chronon의 이미지

커널 소스에서 #define을 많이 사용하는 이유는 무엇 때문인가요?

과거에 그렇게 짠 유물이 남아있는 것인가요? 아니면 다른 특별한 이유가 있습니까?

asiawide의 이미지

chronon wrote:
커널 소스에서 #define을 많이 사용하는 이유는 무엇 때문인가요?

과거에 그렇게 짠 유물이 남아있는 것인가요? 아니면 다른 특별한 이유가 있습니까?

const 로 하던 enum 으로 하던 조건부 컴파일 을 할 수 없기 때문이 아닐까요? -.-

#define 보다는 const 를 쓰려고 하지만

const int SIZE = 100;

xxxx()
{
int babo[SIZE];
}

이런 경우가 종종 있어서.. -_-; 종종 #define 을 그냥 쓰고는 합니다.[/code]

doldori의 이미지

매크로는 단순한 텍스트 대치 방식이기 때문에 scope나 타입은 깡그리 무시하는
무지막지한(blunt) 놈이죠. 그래서 매크로로 인해 컴파일 에러가 났을 때 그 원인이
매크로라는 것을 알아내는 것도 쉽지 않고, 매크로가 원인이라는 것을 알았을 때는
무척 짜증이 나더군요. 컴파일 에러라도 난다면 뭔가 잘못됐다는 바로 알 수 있으니
그나마 괜찮은 편이지만, 의도하지 않은 코드로 컴파일이 되면 정말 큰 문제가 됩니다.
매크로가 문제를 일으키는 예를 한 번 보시죠.

http://www.testors.net/tt/index.php?pl=158&ct1=1

서지훈 wrote:
저 같은 경우 상수는 최대한 const를 이용해서 사용을 할려 합니다.

저도 그렇습니다. 그런데 C90에서 const 정수형은 변경 불가능하다는 의미일 뿐
상수 수식으로 취급되지 않으므로 배열 선언시 이것을 쓰는 것은 불가능하죠.
const int size = 10;
int a[size]; // invalid in C90, valid in C99 and C++

C99에서 이것이 허용되는 이유가 C++과 다르긴 합니다. 어쨌든 C90에서는 매크로
대신에 enum을 쓰는 것이 좀 어색하긴 해도 안전해 보입니다.
dgsquare의 이미지

Quote:
if(0 == a)

좋은 것을 배웠네여 ^^; 안그래도 '=='연산자의 위험성은 항상 걸리적 거렸는데-

참, 상수로 선언된 경우도 값이 변경이 되는 경우가 있더군여.

#include <stdio.h>

   void sub(int *a, int *b);

   int main(void)
   {
       const int a = 1;
       int b = 2;
       sub(&a, &b);

       printf("a = %d, b= %d\n", a, b);

       return 0;
   }

   void sub(int *a, int *b)
   {
       *(a) = *(b);
   }

물론 컴파일러가 경고메세지는 보내줍니다. 컴파일여부는 옵션에 따른 차이일것 같습니다.
(PLC수업을 듣다 심심해서 해보았는데, 그냥 참고하세여^^)

그나저나 Kerighan아저씨가 저렇게 예기한 이유를 아시는 분 있나여?

angpoo의 이미지

#define MAXROW 80
이렇게 상수를 정의 하면 디버깅할때 조금 번거로와질 수 있죠.
소스를 보지 않고는 MAXROW값을 알 수 없으니까요.

매크로로 사용할때 의외의 결과가 나올 수도 있고요.
#define MAX(a,b) ((a)>(b))?(a):(b)
이렇게 만들어 놓고
MAX(a++,b) 같은식으로 써버린다면 a값이 2가 늘어나는 일도 생길 수 있죠

if (a==0), if (0==a)
저는 전자를 추천합니다.
읽기 편하거든요 a가 0이면... 이걸 0과 a가 같으면? 이건 좀 어색하잖아요.
if (a==0)을 실수로 if (a=0)이라고 쓰더라도 컴파일시 경고가 발생하기때문에 실수 할까봐 일부러 뒤집어 쓸 필요는 없습니다.
if (a=0)이 필요한 경우는 if ((a=0)) 이렇게 씁니다.

doldori의 이미지

dgsquare wrote:
참, 상수로 선언된 경우도 값이 변경이 되는 경우가 있더군여.

const 개체를 변경하는 결과는 정의되지 않습니다.

dgsquare wrote:
그나저나 Kerighan아저씨가 저렇게 예기한 이유를 아시는 분 있나여?

케리건(Kerrigan)은 여자예요. ^^;
dgsquare의 이미지

Quote:
케리건(Kerrigan)은 여자예요. ^^;

순간 당황했습니다 -_-......
whitelazy의 이미지

angpoo wrote:

if (a==0), if (0==a)
저는 전자를 추천합니다.
읽기 편하거든요 a가 0이면... 이걸 0과 a가 같으면? 이건 좀 어색하잖아요.
if (a==0)을 실수로 if (a=0)이라고 쓰더라도 컴파일시 경고가 발생하기때문에 실수 할까봐 일부러 뒤집어 쓸 필요는 없습니다.
if (a=0)이 필요한 경우는 if ((a=0)) 이렇게 씁니다.

모든 컴파일러가 다 경고해주는것은 아닙니다...
요즘 컴파일러 많이 좋아졌다지만 -_-;;
모든상황에서 좋은 컴파일러 쓸수있는건 아니죠 :evil:
특히나 임베디드쪽 가면 무슨일이 일어날지는 -_-; 가뜩이나 버그도 많구요 ;;
아아... 물론 저두 전자 '만' 씁니다.. 아직 후자의 형태는 뭔가 어색해서
익명 사용자의 이미지

#define 으로 선언한것은 컴파일에 들어가기 전단계인
프로프로세싱단계에서 처리되는 매크로입니다.
소스를 매크로확장하여 컴파일러가 다시 만든다는....

간단하게 다음을 해보시면,

$ more xx.c
#define MAX 100
main()
{
   printf("%d\n", MAX);
   return 0;
}
$ gcc -E xx.c
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "xx.c"

main()
{
   printf("%d\n", 100);
   return 0;
}

이렇게 컴파일전 프리프로세싱에서 해놓은 소스를 Lexical분석기(컴파일러 1단계)로 넣게 됩니다.
컴파일러 입장에서, 본격 컴파일단계에서 MAX라는 Lexical 심볼은 없지요. 존재하지 않습니다. 단지 100이라는 숫자만이...
그렇다면, const어쩌구 하면 존재하나요? 음.. 쿵~

* 노여워마시고 다음글도...
저는 #define을 아주 즐겨씁니다. 이유는? 그냥..입니다. :twisted:

익명 사용자의 이미지

Quote:
그렇다면, const어쩌구 하면 존재하나요? 음.. 쿵~

그렇다면, enum어쩌구 하면 존재하나요? 음.. 쿵~

댓글 달기

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