“정적 const”vs“#define”vs“enum”


585

C의 아래 진술 중에서 어느 것이 더 나은가요?

static const int var = 5;

또는

#define var 5

또는

enum { var = 5 };

35
흥미롭게도 이것은 stackoverflow.com/questions/1637332/static-const-vs-define거의 동일한 질문 입니다. 유일한 차이점은 그 질문이 C ++에 관한 것이고 이것이 하나의 C에 관한 것입니다. 내 대답은 C ++에 국한되어 있기 때문에 그것들이 동일하지는 않지만 다른 사람들은 동의하지 않을 수 있다고 말합니다.
TED

53
동일하지 않습니다. 호환성 이유로 C ++에서 C 구문을 허용하는 영역이 많이 있습니다. 이 경우 "X를 수행하는 가장 좋은 방법은 무엇입니까?"와 같은 질문은 C ++에서 다른 답변을 갖습니다. 예를 들어 객체 초기화.
MSalters


이것은 어떻게 의견에 근거하지 않습니까? 그들은 각각 다른 목적을 가지고 있습니다
Sam Hammamy

1
@RobertSsupportsMonicaCellio, 예. 친애하는 감사합니다
Vijay

답변:


690

필요한 가치에 따라 다릅니다. 당신 (그리고 지금까지 다른 사람들)은 세 번째 대안을 생략했습니다.

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

이름 선택에 관한 문제를 무시하면 다음과 같습니다.

  • 포인터를 주위에 전달해야하는 경우 (1)을 사용해야합니다.
  • (2)는 분명히 옵션이므로 포인터를 전달할 필요가 없습니다.
  • (1)과 (3) 모두 디버거의 심볼 테이블에 심볼이있어 디버깅이 쉬워집니다. (2)에 기호가 없을 가능성이 높으며 그 의미가 무엇인지 궁금해합니다.
  • (1) 전역 범위에서 배열의 차원으로 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • (1) 함수 범위에서 정적 배열의 차원으로 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • C99에서는이 모든 것을 로컬 어레이에 사용할 수 있습니다. 기술적으로 (1)을 사용하는 것은 VLA (가변 길이 배열)를 사용한다는 것을 의미하지만 'var'이 참조하는 차원은 물론 크기 5로 고정됩니다.
  • (1) 스위치 문과 같은 장소에서는 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • (1) 정적 변수를 초기화하는 데 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • (2) 전 처리기에서 사용하기 때문에 변경하고 싶지 않은 코드를 변경할 수 있습니다. (1)과 (3)은 모두 예상치 못한 부작용이 없습니다.
  • 프리 프로세서에 (2)가 설정되어 있는지 여부를 감지 할 수 있습니다. (1)도 (3)도 허용하지 않습니다.

따라서 대부분의 상황에서 대안보다 '열거'를 선호합니다. 그렇지 않으면 첫 번째 글 머리 기호와 마지막 글 머리 기호가 제어 요소가 될 가능성이 높으며 한 번에 두 가지를 모두 만족시켜야하는 경우 더 열심히 생각해야합니다.

C ++에 대해 묻는다면 매번 옵션 (1) (정적 const)를 사용합니다.


111
환상적인 목록! 한 가지 단점 enumint([C99] 6.7.2.2/3) 로 구현된다는 것 입니다. A를 #define사용하면 부호없는 문자 와 긴 문자 UL접미사 를 지정할 const수 있으며 유형 을 지정할 수 있습니다. enum일반적인 유형 변환에 문제가 발생할 수 있습니다.
Gauthier

37
(2) 사람들은 항상 유형 안전에 대해 불평합니다. 왜 "#define var ((int) 5)"를 사용하지 않는지 이해하지 못하고 정의와 함께 유형 안전을 얻습니다.
Ingo Blackman

6
@RedX : 공간이 걱정되는 매우 독특한 환경에 있어야합니다. 즉, 여분의 공간 enum#define사용 하지도 않습니다 . 값은 데이터 세그먼트 또는 힙 또는 스택에 스토리지가 할당되지 않고 명령의 일부로 오브젝트 코드에 나타납니다. 에 대해 약간의 공간이 할당 static const int되지만 주소를 사용하지 않으면 컴파일러가 공간을 최적화 할 수 있습니다.
Jonathan Leffler

15
enum의 (및 static const)에 대한 또 다른 '투표' : 변경할 수 없습니다. define될 수 #undefineD '여기서 enumstatic const소정 값으로 고정된다.
Daan Timmer

15
@QED : 아니요, 감사합니다. 간단한 상수는 괄호 밖에서 안전합니다. 또는 합법적으로 컴파일 할 것으로 예상되는 프로그램이 괄호 안에 5가 없어서 어떻게 변경되는지 보여주십시오. 함수 스타일 매크로에 대한 주장이거나 표현식에 연산자가있는 경우 괄호를 포함하지 않았다고 비난하는 것이 옳습니다. 그러나 여기서는 그렇지 않습니다.
Jonathan Leffler

282

일반적으로 말하면:

static const

범위를 존중하고 형식이 안전하기 때문입니다.

내가 볼 수있는 유일한주의 사항 : 명령 줄에 변수를 정의하려는 경우. 여전히 대안이 있습니다.

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

가능하면 매크로 / 줄임표 대신 유형이 안전한 대안을 사용하십시오.

매크로와 함께 가야하는 경우 (예 : __FILE__또는 __LINE__) 매크로 이름을 매우 신중하게 지정하는 것이 좋습니다. 명명 규칙에서 Boost 는 프로젝트 이름으로 시작하는 모든 대문자를 권장합니다 (여기서는 BOOST_ ), 라이브러리를 숙독하는 동안 (일반적으로) 그 뒤에 특정 영역 (라이브러리)의 이름과 그 뒤에 의미있는 이름이 붙는 것을 알 수 있습니다.

그것은 일반적으로 긴 이름을 만듭니다 :)


2
동의-또한 #define을 사용하면 전처리 기가 구문을 인식하지 못하기 때문에 코드를 조작 할 위험이 있습니다.
NeilDurant 2009

10
#if #if #보다 #if을 사용하는 것이 좋지만 그렇지 않으면 동의합니다. +1.
Tim Post

58
이것이 표준 C ++ 전도입니다. 아래의 답변은 옵션이 실제로 의미하는 바를 명확하게 설명합니다. 특히 : 나는 "정적 const"에 문제가있었습니다. 누군가 헤더 파일에 약 2000 개의 "상수"를 정의하는 데 사용했습니다. 그런 다음이 헤더 파일은 약 100 개의 ".c"및 ".cpp"파일에 포함되었습니다. => "consts"의 경우 8MB. 큰. 네, 당신은 참조되지 않은 const를 제거하기 위해 링커를 사용할 수 있다는 것을 알고 있지만, 여전히 참조되는 "consts"를 남겨 둡니다. 공간이 부족하면이 답변에 문제가 있습니다.
Ingo Blackman

2
@IngoBlackman : 좋은 컴파일러를 사용하면 static주소를 가진 사람 만 남아 있어야합니다. 주소를 가져 가면 #define또는 enum주소를 사용할 수 없었습니다 ... 그래서 실제로 어떤 대안을 사용할 수 있는지 보지 못했습니다. "컴파일 시간 평가"를 없앨 수 있다면 extern const대신 찾으실 수 있습니다 .
Matthieu M.

15
@ 팀 포스트 : #if이상 바람직 수 있습니다 #ifdef부울 플래그 있지만,이 경우에는 불가능 정의 할 것 var같은 0명령 줄에서. 따라서이 경우에 대한 법적 가치가있는 한 #ifdef더 의미 0var있습니다.
Maarten

108

C에서는 구체적으로? 사용 : C에서 정답은 #define(해당되는 경우, 또는 enum)

const객체 의 범위 지정 및 타이핑 속성을 갖는 것이 유리하지만 , 실제로 constC의 객체 (C ++와 반대)는 실제 상수가 아니므로 대부분의 실제 경우에는 쓸모가 없습니다.

따라서 C에서 선택은 상수를 어떻게 사용할 계획인지에 따라 결정되어야합니다. 예를 들어, const int개체를 case레이블 로 사용할 수 없습니다 (매크로가 작동하는 동안). const int매크로를 작동하는 동안 객체를 비트 필드 너비로 사용할 수 없습니다 . C89 / 90에서는 const객체를 사용하여 배열 크기를 지정할 수 없습니다 (매크로가 작동하는 동안). C99에서도 VLAconst 가 아닌 배열 이 필요할 때 객체를 사용하여 배열 크기를 지정할 수 없습니다 .

이것이 당신에게 중요하다면 그것은 당신의 선택을 결정할 것입니다. 대부분의 경우 #defineC 에서 사용하는 것 외에는 선택의 여지가 없습니다 enum. C-에서 진정한 상수를 생성하는 다른 대안을 잊지 마십시오 .

C ++ const객체는 진정한 상수이므로 C ++에서는 const변형 을 선호하는 것이 거의 항상 좋습니다 ( staticC ++ 에서는 명시 적으로 필요하지 않음 ).


6
"당신은 케이스 라벨로 CONST의 int 객체를 사용할 수 없습니다 (동안 매크로 의지 작업)"---> 나는 그것을이 작동 스위치 - 경우에 C의 CONST의 INT 변수를 테스트 한이 문장에 대해서 ....

8
@ john : 글쎄, 테스트 한 코드를 제공하고 특정 컴파일러의 이름을 지정해야합니다. const int모든 버전의 C 언어에서 대소 문자 레이블에 객체를 사용하는 것은 불법입니다. (물론 컴파일러는 비표준 C ++와 같은 언어 확장으로 자유롭게 지원할 수 있습니다.)
AnT

11
"... 따라서 대부분의 실제 경우에는 쓸모가 없습니다 ." 동의하지 않습니다. 이름을 상수 식으로 사용할 필요가없는 한 완벽하게 유용합니다. C에서 "constant"라는 단어는 컴파일 타임에 평가할 수있는 것을 의미합니다. const읽기 전용을 의미합니다. const int r = rand();완벽하게 합법적입니다.
Keith Thompson

C ++에서 그것을 사용하는 것이 좋습니다 constexpr에 비해 const특별히와 stl같은 용기 arraybitset.
Mayukh Sarkar

1
@ john 당신 switch()case하나가 아니라 진술에서 테스트해야 합니다. 방금 이것에 붙잡 혔습니다 ☺
Hi-Angel

32

차이 static const하고 #define있다는 이전의 메모리 사용 및 저장을 위해 나중에 사용하지 않는 메모리. 둘째,의 주소는 전달할 수 없지만의 주소 #define는 전달할 수 있습니다 static const. 실제로 그것은 우리가 어떤 환경에 있는지에 따라 다르며,이 두 가지 중에서 하나를 선택해야합니다. 둘 다 다른 상황에서 최선을 다하고 있습니다. 하나가 다른 것보다 낫다고 가정하지 마십시오 ... :-)

만약 그렇다면, Dennis Ritchie 는 최선을 다했을 것입니다 ... hahaha ... :-)


6
메모리를 언급하면 ​​+1이지만 일부 임베디드 시스템에는 여전히 그다지 많지 않지만 정적 const를 사용하여 시작하고 필요한 경우에만 #defines로 변경합니다.
fluffyben

3
방금 테스트했습니다. 실제로 const int는 #define 또는 enum에 비해 추가 메모리를 사용합니다. 임베디드 시스템을 프로그래밍하기 때문에 추가 메모리 사용량을 감당할 수 없습니다. 따라서 #define 또는 enum을 사용하는 것으로 되돌아갑니다.
Davide Andrea

2
실제로 말하자면 a const가 메모리를 사용 한다는 것은 사실이 아닙니다 . GCC (4.5.3 및 몇 가지 최신 버전으로 테스트)는 const int-O3을 사용할 때 코드에서 직접 리터럴로 쉽게 최적화합니다 . 따라서 RAM 내장 개발 (예 : AVR)을 수행하지 않으면 GCC 또는 다른 호환되는 컴파일러를 사용하는 경우 C const를 안전하게 사용할 수 있습니다. 나는 그것을 테스트하지는 않았지만 Clang이 btw와 같은 일을 할 것으로 기대합니다.
Raphael

19

C #define에서는 훨씬 더 인기가 있습니다. 예를 들어 배열 크기를 선언하기 위해 해당 값을 사용할 수 있습니다.

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C는 static const내가 아는 한이 문맥에서 s 를 사용할 수 없습니다 . C ++에서는 이러한 경우 매크로를 피해야합니다. 당신은 쓸 수 있습니다

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

static내부 연결은 const이미 [C ++에서만]에 의해 암시되기 때문에 제외하십시오 .


1
"내부 연결"이란 무엇입니까? const int MY_CONSTANT = 5;하나의 파일을 가지고 다른 파일로 액세스 할 수 있습니다 extern const int MY_CONSTANT;. const기본 동작 변경 에 대한 표준 (최소한 C99) 정보를 찾을 수 없습니다 "6.2.2 : 5 개체에 대한 식별자 선언에 파일 범위가 있고 스토리지 클래스 지정자가없는 경우 연결은 외부입니다".
Gauthier

@Gauthier : 죄송합니다. 나는 "C ++ 언어로 이미 const에 의해 암시되어있다"고 말해야했다. 이것은 C ++에만 해당됩니다.
sellibitze

@sellibitze 수많은 의견 대신에 몇 가지 주장을 보는 것이 좋습니다. 진정한 주장에 대한 보너스가 있다면, 당신은 그것을 얻었습니다!
Paul

1
C99 기준으로 두 번째 스 니펫은 합법적입니다. barVLA (가변 길이 배열)입니다. 컴파일러는 길이가 일정한 것처럼 코드를 생성 할 수 있습니다.
Keith Thompson

14

constC 의 또 다른 단점은 다른를 초기화 할 때 값을 사용할 수 없다는 것 const입니다.

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

컴파일러는 상수로 간주하지 않기 때문에 const에서도 작동하지 않습니다.

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

const이 경우에는 타이핑을 사용하게되어 기쁩니다 . 그렇지 않으면 ...


5
게임에 조금 늦었지만이 질문은 또 다른 질문에서 나왔습니다. static uint8_t const ARRAY_SIZE = 16;갑자기 모든 컴파일이 더 이상 수행되지 않는 이유를 추적 하는 #define ARRAY_SIZE 256것은 특히 어려운 일 입니다. 모든 대문자 이름 ARRAY_SIZE이 문제를 요구하고 있습니다. 매크로를 위해 ALL_CAPS를 예약하고 ALL_CAPS 형식이 아닌 매크로를 정의하지 마십시오.
David Hammen

@David : 내가 따를 건전한 조언.
Gauthier

1
4 년 후 당신은 왜 내가 "못"할 수 없는지 알아 내는데 많은 시간을 절약했습니다 const. 이것은 더 많이 upvoted 할 수 있습니다!
Plouff

11

도망 갈 수 있다면 static const 많은 장점이 있습니다. 일반적인 범위 원칙을 준수하고 디버거에서 볼 수 있으며 일반적으로 변수가 따르는 규칙을 따릅니다.

그러나 최소한 원래 C 표준에서는 실제로 일정하지 않습니다. 당신이 사용하는 경우 #define var 5, 당신은 쓸 수 int foo[var];선언으로,하지만 당신과 함께 컴파일러 확장 "를 제외하고 (그렇게 할 수 없습니다 static const int var = 5;. 이것은 ++은 C의 경우가 아니라 static const버전 어디서나 사용할 수 있습니다#define 버전 캔, 그리고 믿을 C99의 경우도 마찬가지입니다.

그러나 #define소문자 이름 으로 상수 이름을 지정하지 마십시오 . 번역 단위가 끝날 때까지 해당 이름을 사용할 수 있습니다. 매크로 상수는 사실상 고유의 네임 스페이스에 있어야하며, 일반적으로 접두사가있는 모든 대문자입니다.


6
불행히도 C99에서는 그렇지 않습니다. constC99에서는 여전히 실제 상수가 아닙니다. constC99에서 a 를 사용하여 배열 크기를 선언 할 수 있지만 C99는 가변 길이 배열을 지원하므로 가능합니다. 이러한 이유로 VLA가 허용되는 경우에만 작동합니다. 예를 들어, C99에서도을 사용하여 const의 멤버 배열 크기를 선언 할 수는 없습니다 struct.
AnT

C99가 그렇게하지 않는 것이 맞지만 GCC (4.5.3으로 테스트)는 const int마치 마치 C ++ const 나 매크로 인 것처럼 크기로 배열을 완벽하게 초기화 할 수있게 해줍니다. 표준에서 GCC의 편차에 의존하고 싶을지는 물론 당신이 선택하는 것입니다 .GCC 또는 Clang 이외의 다른 컴파일러를 사용하여 실제로 볼 수 없다면, 후자는 동일한 기능을 가지고 있습니다 (Clang으로 테스트 됨) 3.7).
Raphael

7

#define 대신 const를 사용하는 것이 좋습니다. const가 컴파일러에 의해 처리되고 #define이 전처리기에 의해 처리되기 때문입니다. #define 자체는 코드의 일부가 아닙니다 (거의 말하기).

예:

#define PI 3.1416

컴파일러에서는 기호 이름 PI를 절대로 볼 수 없습니다. 소스 코드가 컴파일러에 도달하기 전에 프리 프로세서에 의해 제거 될 수 있습니다. 결과적으로 이름 PI가 기호 테이블에 입력되지 않을 수 있습니다. 오류 메시지가 PI가 아닌 3.1416을 참조 할 수 있으므로 상수 사용과 관련된 컴파일 중 오류가 발생하면 혼동 될 수 있습니다. PI가 작성하지 않은 헤더 파일에 정의 된 경우 해당 3.1416의 출처를 모를 것입니다.

프로그래밍하는 이름이 심볼 테이블에 없을 수도 있기 때문에이 문제는 심볼릭 디버거에서도 발생할 수 있습니다.

해결책:

const double PI = 3.1416; //or static const...

6

#define var 5당신이 같은 것을 가지고 있다면 문제를 일으킬 것 mystruct.var입니다.

예를 들어

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

전처리 기가이를 대체하고 코드는 컴파일되지 않습니다. 이러한 이유로, 전통적인 코딩 스타일은 모든 상수가 #define충돌을 피하기 위해 대문자를 사용하도록 제안합니다 .


6

한 가지 차이점을 보여주기 위해 빠른 테스트 프로그램을 작성했습니다.

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

이것은 다음과 같은 오류 및 경고로 컴파일됩니다.

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

define에서 경고를 표시하면 enum에서 오류가 발생합니다.


4

정의

const int const_value = 5;

항상 상수 값을 정의하지는 않습니다. 일부 컴파일러 (예 : tcc 0.9.26 )는 "const_value"라는 이름으로 식별 된 메모리 만 할당합니다. 식별자 "const_value"를 사용하면이 메모리를 수정할 수 없습니다. 그러나 여전히 다른 식별자를 사용하여 메모리를 수정할 수 있습니다.

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

이것은 정의를 의미

#define CONST_VALUE 5

어떤 방법으로도 수정할 수없는 상수 값을 정의하는 유일한 방법입니다.


8
포인터를 사용하여 상수 값을 수정하는 것은 정의되지 않은 동작입니다. 당신이 거기에 가고 싶다면 #define기계 코드를 편집하여 수정할 수도 있습니다.
ugoren

당신은 부분적으로 옳습니다. Visual Studio 2012를 사용하여 코드를 테스트 한 결과 인쇄 5됩니다. 그러나 #define전 처리기 매크로이기 때문에 수정할 수 없습니다 . 바이너리 프로그램에는 존재하지 않습니다. CONST_VALUE사용 된 모든 장소를 수정 하려면 하나씩 수행해야합니다.
user2229691

3
@ugoren :을 쓴 #define CONST 5다음 if (CONST == 5) { do_this(); } else { do_that(); }컴파일러가 else분기를 제거 한다고 가정 해 봅시다 . CONST6 으로 변경 하기 위해 기계어 코드 편집을 어떻게 제안 합니까?
키이스 톰슨

@ KeithThompson, 나는 그것이 쉽고 안정적으로 수행 할 수 있다고 말한 적이 없습니다. 그냥 그 #define방탄 없습니다.
ugoren

3
@ugoren : 내 요점은 "머신 코드 편집"이 a 값을 변경하는 효과를 복제하는 합리적인 방법이 아니라는 것 #define입니다. 그렇게하는 유일한 방법은 소스 코드를 편집하고 다시 컴파일하는 것입니다.
Keith Thompson

4

문제는 정수에 관한 것이지만 상수 구조 또는 문자열이 필요한 경우 #define 및 enum은 쓸모가 없다는 점에 주목할 가치가 있습니다. 이것들은 보통 포인터로 함수에 전달됩니다. (문자열이 필요하고 구조가 훨씬 효율적입니다.)

정수의 경우 메모리가 매우 제한된 임베디드 환경에 있으면 상수가 저장되는 위치와 액세스가 컴파일되는 방법에 대해 걱정해야 할 수도 있습니다. 컴파일러는 런타임에 두 개의 const를 추가 할 수 있지만 컴파일시 두 개의 #defines를 추가 할 수 있습니다. #define 상수는 하나 이상의 MOV [즉시] 명령어로 변환 될 수 있으며, 이는 상수가 프로그램 메모리에 효과적으로 저장됨을 의미합니다. const 상수는 데이터 메모리의 .const 섹션에 저장됩니다. 하버드 아키텍처를 사용하는 시스템에서는 성능과 메모리 사용량에 차이가있을 수 있지만 크기는 작을 수 있습니다. 내부 루프의 하드 코어 최적화에 중요 할 수 있습니다.


3

Matthieu가 말한 것처럼 "항상 최고"에 대한 답이 있다고 생각하지 마십시오.

static const

안전합니다. 그러나 내 가장 큰 애완 동물 #defineVisual Studio 에서 디버깅 할 때 변수를 볼 수 없다는 것입니다. 기호를 찾을 수 없다는 오류가 발생합니다.


1
"변수를 볼 수 없습니다"그렇습니다. 변수가 아닙니다. 바뀌지 않는 이유는 무엇입니까? 라벨을 검색하여 사용되는 모든 곳에서 찾을 수 있습니다. #define을 시청해야하는 이유는 무엇입니까?
Marshall Eubanks

3

또한 #define적절한 범위 지정을 제공하지만 "실제"상수처럼 동작하는에 대한 대안 은 "enum"입니다. 예를 들면 다음과 같습니다.

enum {number_ten = 10;}

많은 경우 열거 된 유형을 정의하고 해당 유형의 변수를 작성하는 것이 유용합니다. 그렇게하면 디버거가 열거 이름에 따라 변수를 표시 할 수 있습니다.

그러나 C ++에서 열거 형은 정수와의 호환성이 제한적입니다. 예를 들어, 기본적으로 산술을 수행 할 수 없습니다. 열거 형에 대한 호기심이 많은 기본 동작이라는 것을 알았습니다. C ++이 일반적으로 C와 호환되도록하려면 "엄격 열거 형"형식을 사용하는 것이 좋았지 만 "enum"형식의 기본 동작은 정수와 호환 가능해야한다고 생각합니다.


1
C에서 열거 상수는 항상 유형 int이므로 "enum hack"은 다른 정수 유형과 함께 사용할 수 없습니다. 열거 은 구현 정의 정수형과 반드시 ​​호환 될 필요 int는 없지만,이 경우에는 익명이므로 아무리 중요하지도 않습니다.
Keith Thompson

@KeithThompson : 위의 내용을 썼기 때문에 컴파일러 int가 열거 형 변수 이외의 유형 (컴파일러가 허용) 이외의 유형 을 할당하고 그러한 변수에 할당하려고 하면 MISRA-C가 스 쿼크된다는 것을 읽었습니다. 자체 열거 형의 멤버 표준위원회가 지정된 의미론으로 정수 유형을 선언하는 이식 가능한 방법을 추가하기를 바랍니다. 크기에 상관없이 모든 플랫폼 char은 컴파일러가 AND R0,#0xFFFF명령을 많이 추가 하거나 이에 상응하는 명령 을 추가해야하더라도 mod 65536을 래핑 할 유형을 선언 할 수 있어야합니다 .
supercat

uint16_t물론 열거 형이 아닌을 사용할 수 있습니다 . 사용자가 주어진 열거 유형을 나타내는 데 사용되는 정수 유형을 지정하게하는 것이 좋지만 개별 값에 대해 typedeffor uint16_t및 일련의 #defines를 사용 하여 동일한 효과를 얻을 수 있습니다 .
Keith Thompson

1
@ KeithThompson : 역사적인 이유로 우리는 일부 플랫폼이 2U < -1L참으로 평가 되고 다른 플랫폼은 거짓으로 평가 된다는 사실에 고착하고 있으며, 이제 일부 플랫폼이 사이에 uint32_t그리고 int32_t서명 된 것과 의 비교를 구현한다는 사실에 고착 하고 있습니다 그리고 일부는 서명되지 않았지만위원회가 의미가 모든 컴파일러에서 일관된 유형을 포함하는 C의 상위 호환 호환 후속 작업을 정의 할 수 없음을 의미하지는 않습니다.
supercat

1

간단한 차이점 :

사전 처리시 상수는 해당 값으로 대체됩니다. 따라서 역 참조 연산자를 정의에 적용 할 수 없지만 역 참조 연산자를 변수에 적용 할 수 있습니다.

가정 하듯이, 정적 const보다 define이 빠릅니다.

예를 들어,

#define mymax 100

넌 못해 printf("address of constant is %p",&mymax); .

하지만

const int mymax_var=100

넌 할 수있어 printf("address of constant is %p",&mymax_var); .

더 명확하게하기 위해, 정의는 사전 처리 단계에서 값으로 대체되므로 프로그램에 변수가 저장되어 있지 않습니다. 정의가 사용 된 프로그램의 텍스트 세그먼트에있는 코드 만 있습니다.

그러나 정적 const의 경우 어딘가에 할당 된 변수가 있습니다. gcc의 경우 정적 const가 프로그램의 텍스트 세그먼트에 할당됩니다.

위의 참조 연산자에 대해 말하고 싶기 때문에 역 참조를 참조로 바꿉니다.


1
당신의 대답은 매우 잘못되었습니다. 이것은 C에 관한 것이며, 귀하의 대답은 C ++과 관련이 있으며 const한정자에 대한 의미가 매우 다릅니다 . C에는 열거 상수 이외의 기호 상수가 없습니다 . A const int는 변수입니다. 또한 언어와 특정 구현을 혼동합니다. 물체를 어디에 둘 필요가 없습니다. 그리고 gcc의 경우에도 마찬가지입니다. 일반적으로 섹션에 const한정된 변수를 배치 .rodata합니다. 그러나 그것은 목표 플랫폼에 달려 있습니다. 그리고 당신은 주소 연산자를 의미합니다 &.
이 사이트에 대해 너무 정직합니다.

0

우리는 MBF16X에서 생성 된 어셈블러 코드를 살펴 보았습니다. 두 변형 모두 산술 연산 (예 : ADD Immediate)에 대해 동일한 코드를 생성합니다.

그래서 const int동안 유형 검사에 대한 선호 #define된 스타일입니다. 아마도 컴파일러마다 다를 수 있습니다. 따라서 생성 된 어셈블러 코드를 확인하십시오.


-1

내가 옳은지는 확실하지 않지만 내 의견으로는 #defined 값을 호출하는 것이 일반적으로 선언 된 다른 변수 (또는 const 값)를 호출하는 것보다 훨씬 빠릅니다. 프로그램이 실행 중이고 정상적으로 선언 된 변수를 사용해야 할 때 해당 변수를 얻으려면 메모리의 정확한 위치로 이동해야하기 때문입니다.

#defined 값을 사용할 때 반대로 프로그램은 할당 된 메모리로 이동할 필요가 없으며 값을 가져옵니다. 경우 #define myValue 7프로그램을 호출하고 myValue, 그것이 바로 호출 할 때와 완전히 동일하게 동작합니다 7.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.