program tip

"정적 const"vs "#define"vs "enum"

radiobox 2020. 10. 4. 10:48
반응형

"정적 const"vs "#define"vs "enum"


C에서 아래 문장 중 어느 것을 사용하는 것이 더 낫습니까?

static const int var = 5;

또는

#define var 5

또는

enum { var = 5 };

일반적으로 말하면:

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__or __LINE__)를 사용해야하는 경우 매크로 이름을 매우 신중하게 지정하는 것이 좋습니다. 이름 지정 규칙에서 Boost 는 프로젝트 이름으로 시작하는 모든 대문자를 권장합니다 (여기서는 BOOST_ ), 라이브러리를 자세히 살펴보면 (일반적으로) 특정 영역 (라이브러리)의 이름과 의미있는 이름이 뒤 따르는 것을 알 수 있습니다.

일반적으로 긴 이름을 만듭니다. :)


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

  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) switch 문과 같은 장소에서는 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • (1) 정적 변수를 초기화하는 데 사용할 수 없습니다. (2)와 (3) 모두 가능합니다.
  • (2) 전 처리기에서 사용하기 때문에 변경하고 싶지 않은 코드를 변경할 수 있습니다. (1)과 (3) 둘 다 이와 같은 예기치 않은 부작용이 없습니다.
  • 전처리기에 (2)가 설정되었는지 여부를 감지 할 수 있습니다. (1)도 (3)도 그것을 허용하지 않습니다.

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

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


C에서 구체적으로? C에서 정답은 다음과 같습니다. 사용 #define(또는 적절한 경우 enum)

const객체 의 범위 지정 및 유형 지정 속성을 갖는 것이 유익하지만 실제로 constC의 객체 (C ++와 반대)는 실제 상수가 아니므로 대부분의 실제 사례에서 일반적으로 쓸모가 없습니다.

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

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

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


차이 static const하고 #define있다는 이전의 메모리 사용 및 저장을 위해 나중에 사용하지 않는 메모리. 둘째, 당신은의 주소를 전달할 수 없습니다 #define당신이의 주소를 전달할 수있는 반면 static const. 사실 우리가 처한 상황에 따라이 둘 중 하나를 선택해야합니다. 둘 다 다른 상황에서 최선을 다합니다. 하나가 다른 것보다 낫다고 생각하지 마십시오 ... :-)

그랬다면 Dennis Ritchie 는 최고의 것을 홀로 유지했을 것입니다 ... hahaha ... :-)


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 ++에서만] 함축되어 있기 때문에 생략 할 수도 있습니다.


constC 의 또 다른 단점은 다른 .NET을 초기화 할 때 값을 사용할 수 없다는 것 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이 경우 typed를 사용하면 좋겠습니다 . 그렇지 않으면 ...


그것으로 벗어날 수 있다면 static const많은 이점이 있습니다. 일반 범위 원칙을 따르고 디버거에서 볼 수 있으며 일반적으로 변수가 따르는 규칙을 따릅니다.

그러나 적어도 원래의 C 표준에서는 실제로 상수가 아닙니다. 를 사용 하면 선언으로 #define var 5작성할 수 int foo[var];있지만 그렇게 할 수는 없습니다 (컴파일러 확장으로 제외 ") static const int var = 5;. 이것은 static const버전이 가능한 모든 곳에서 #define버전을 사용할 수있는 C ++의 경우가 아닙니다. C99에서도 마찬가지입니다.

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


#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...

#define var 5 will cause you trouble if you have things like mystruct.var.

For example,

struct mystruct {
    int var;
};

#define var 5

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

The preprocessor will replace it and the code won't compile. For this reason, traditional coding style suggest all constant #defines uses capital letters to avoid conflict.


I wrote quick test program to demonstrate one difference:

#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);
}

This compiles with these errors and warnings:

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
        ^

Note that enum gives an error when define gives a warning.


The definition

const int const_value = 5;

does not always define a constant value. Some compilers (for example tcc 0.9.26) just allocate memory identified with the name "const_value". Using the identifier "const_value" you can not modify this memory. But you still could modify the memory using another identifier:

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.

This means the definition

#define CONST_VALUE 5

is the only way to define a constant value which can not be modified by any means.


Don't think there's an answer for "which is always best" but, as Matthieu said

static const

is type safe. My biggest pet peeve with #define, though, is when debugging in Visual Studio you cannot watch the variable. It gives an error that the symbol cannot be found.


Incidentally, an alternative to #define, which provides proper scoping but behaves like a "real" constant, is "enum". For example:

enum {number_ten = 10;}

In many cases, it's useful to define enumerated types and create variables of those types; if that is done, debuggers may be able to display variables according to their enumeration name.

One important caveat with doing that, however: in C++, enumerated types have limited compatibility with integers. For example, by default, one cannot perform arithmetic upon them. I find that to be a curious default behavior for enums; while it would have been nice to have a "strict enum" type, given the desire to have C++ generally compatible with C, I would think the default behavior of an "enum" type should be interchangeable with integers.


Although the question was about integers, it's worth noting that #define and enums are useless if you need a constant structure or string. These are both usually passed to functions as pointers. (With strings it's required; with structures it's much more efficient.)

As for integers, if you're in an embedded environment with very limited memory, you might need to worry about where the constant is stored and how accesses to it are compiled. The compiler might add two consts at run time, but add two #defines at compile time. A #define constant may be converted into one or more MOV [immediate] instructions, which means the constant is effectively stored in program memory. A const constant will be stored in the .const section in data memory. In systems with a Harvard architecture, there could be differences in performance and memory usage, although they'd likely be small. They might matter for hard-core optimization of inner loops.


A simple difference:

At pre-processing time, the constant is replaced with its value. So you could not apply the dereference operator to a define, but you can apply the dereference operator to a variable.

As you would suppose, define is faster that static const.

For example, having:

#define mymax 100

you can not do printf("address of constant is %p",&mymax);.

But having

const int mymax_var=100

you can do printf("address of constant is %p",&mymax_var);.

To be more clear, the define is replaced by its value at the pre-processing stage, so we do not have any variable stored in the program. We have just the code from the text segment of the program where the define was used.

However, for static const we have a variable that is allocated somewhere. For gcc, static const are allocated in the text segment of the program.

Above, I wanted to tell about the reference operator so replace dereference with reference.


We looked at the produced assembler code on the MBF16X... Both variants result in the same code for arithmetic operations (ADD Immediate, for example).

So const int is preferred for the type check while #define is old style. Maybe it is compiler-specific. So check your produced assembler code.


I am not sure if I am right but in my opinion calling #defined value is much faster than calling any other normally declared variable (or const value). It's because when program is running and it needs to use some normally declared variable it needs to jump to exact place in memory to get that variable.

In opposite when it use #defined value, the program don't need to jump to any allocated memory, it just takes the value. If #define myValue 7 and the program calling myValue, it behaves exactly the same as when it just calls 7.

참고URL : https://stackoverflow.com/questions/1674032/static-const-vs-define-vs-enum

반응형