C 및 C ++에서 ‘const static’은 무엇을 의미합니까? = 42; StackOverflow의 일부 코드에서 이것을

const static int foo = 42;

StackOverflow의 일부 코드에서 이것을 보았고 그것이 무엇을하는지 알 수 없었습니다. 그런 다음 다른 포럼에서 혼란스러운 답변을 보았습니다. 내 추측으로는 foo다른 모듈 에서 상수를 숨기기 위해 C에서 사용된다는 것 입니다. 이 올바른지? 그렇다면 왜 누군가가 그것을 만들 수있는 C ++ 컨텍스트에서 그것을 사용 private합니까?



답변

그것은 C와 C ++ 모두에서 사용됩니다.

짐작했듯이 static파트는 범위를 해당 컴파일 단위 로 제한합니다 . 또한 정적 초기화를 제공합니다. const컴파일러에게 아무도 수정하지 못하도록 지시합니다. 이 변수는 아키텍처에 따라 데이터 또는 bss 세그먼트에 배치되며 읽기 전용으로 표시된 메모리에있을 수 있습니다.

이것이 C가 이러한 변수를 처리하는 방법 (또는 C ++이 네임 스페이스 변수를 처리하는 방법)입니다. C ++에서 표시된 멤버 static는 지정된 클래스의 모든 인스턴스에서 공유됩니다. 비공개인지 여부는 하나의 변수가 여러 인스턴스에서 공유된다는 사실에 영향을주지 않습니다. 데 const코드가를 수정하려고한다면 거기에 당신을 경고합니다.

엄격하게 비공개 인 경우 클래스의 각 인스턴스는 고유 한 버전을 얻습니다 (최적화에도 불구하고).


답변

많은 사람들이 기본적인 대답을하는 듯했으나 아무도 C ++에서 지적하지 const기본값 static에서 namespace레벨 (일부는 잘못된 정보를 주었다). C ++ 98 표준 섹션 3.5.3을 참조하십시오.

먼저 배경 :

번역 단위 : 전 처리기 (재귀 적으로)가 모든 포함 파일을 포함시킨 후의 소스 파일.

정적 연결 : 기호는 번역 단위 내에서만 사용할 수 있습니다.

외부 연결 : 다른 번역 단위에서 기호를 사용할 수 있습니다.

에서 namespace수준

여기에는 전역 이름 공간 일명 전역 변수가 포함 됩니다.

static const int sci = 0; // sci is explicitly static
const int ci = 1;         // ci is implicitly static
extern const int eci = 2; // eci is explicitly extern
extern int ei = 3;        // ei is explicitly extern
int i = 4;                // i is implicitly extern
static int si = 5;        // si is explicitly static

기능 수준에서

static함수 호출 사이에 값이 유지됨을 의미합니다.
함수 static변수 의 의미는 프로그램의 데이터 세그먼트 (스택이나 힙이 아님) 에 있다는 점에서 전역 변수와 유사합니다 . 변수 수명 에 대한 자세한 내용 은 이 질문 을 참조하십시오 static.

에서 class수준

static값이 클래스의 모든 인스턴스간에 공유되며 const변경되지 않음을 의미합니다.


답변

이 코드 줄은 실제로 여러 다른 컨텍스트에서 나타날 수 있으며 거의 ​​동일하게 작동하지만 약간의 차이가 있습니다.

네임 스페이스 범위

// foo.h
static const int i = 0;

i‘은 헤더를 포함하는 모든 번역 단위에 표시됩니다. 그러나 실제로 객체의 주소 (예 : ‘ &i‘)를 사용하지 않는 한 , 컴파일러는 ‘ i‘를 단순히 형식에 안전한 것으로 취급 할 것이라고 확신합니다 0. 두 개 이상의 번역 단위가 ‘ &i‘를 사용하면 각 번역 단위에 대해 주소가 달라집니다.

// foo.cc
static const int i = 0;

i‘에는 내부 연결이 있으므로이 번역 단위 외부에서 참조 할 수 없습니다. 그러나 주소를 사용하지 않는 한 다시 type-safe로 취급 될 가능성이 높습니다 0.

지적 할 가치가있는 한 가지는 다음 선언입니다.

const int i1 = 0;

정확히 동일합니다 static const int i = 0. 로 선언 const되고 명시 적으로 선언되지 않은 네임 스페이스의 변수 extern는 암시 적으로 정적입니다. 이것에 대해 생각해 보면 , ODR을 깨는 것을 피하기 위해 const항상 static키워드를 필요로하지 않고 헤더 파일에서 변수를 선언 할 수 있도록하는 것이 C ++위원회의 의도였습니다 .

클래스 범위

class A {
public:
  static const int i = 0;
};

위의 예에서 표준 i은 주소가 필요하지 않은 경우 ‘ ‘를 정의 할 필요가 없음을 명시 적으로 지정 합니다. 즉, ‘ i‘를 유형 안전 0으로 만 사용 하면 컴파일러가이를 정의하지 않습니다. 클래스와 네임 스페이스 버전의 한 가지 차이점은 ‘ i‘ 의 주소 (두 개 이상의 번역 단위에서 사용되는 경우)가 클래스 멤버에 대해 동일하다는 것입니다. 주소가 사용되는 경우 해당 주소에 대한 정의가 있어야합니다.

// a.h
class A {
public:
  static const int i = 0;
};

// a.cc
#include "a.h"
const int A::i;            // Definition so that we can take the address

답변

작은 공간 최적화입니다.

당신이 말할 때

const int foo = 42;

상수를 정의하는 것이 아니라 읽기 전용 변수를 만듭니다. 컴파일러는 foo를 볼 때마다 42를 사용할만큼 똑똑하지만 초기화 된 데이터 영역에 공간을 할당하기도합니다. 이것은 정의 된대로 foo에 외부 연결이 있기 때문에 수행됩니다. 다른 컴파일 단위는 다음과 같이 말할 수 있습니다.

extern const int foo;

그 가치에 접근하기 위해. 그 컴파일 단위는 foo의 값이 무엇인지 전혀 모르기 때문에 좋은 습관이 아닙니다. 그것은 단지 그것이 const int라는 것을 알고 있고 그것이 사용될 때마다 메모리에서 값을 다시로드해야합니다.

이제 정적임을 선언하여 :

static const int foo = 42;

컴파일러는 일반적인 최적화를 수행 할 수 있지만 “야,이 컴파일 단위 외부의 누구도 foo를 볼 수 없으며 항상 42라는 것을 알고 있으므로 공간을 할당 할 필요가 없습니다.”라고 말할 수도 있습니다.

또한 C ++에서 이름이 현재 컴파일 단위를 이스케이프하지 않도록 방지하는 가장 좋은 방법은 익명 네임 스페이스를 사용하는 것입니다.

namespace {
    const int foo = 42; // same as static definition above
}

답변

‘int’가 없습니다. 그것은해야한다:

const static int foo = 42;

C 및 C ++에서는 로컬 파일 범위 값이 42 인 정수 상수를 선언합니다.

왜 42일까요? 당신이 아직 모른다면 (그리고 당신이 모른다는 것을 믿기 힘들다), 그것은 생명, 우주, 모든 것에 대한 답에 대한 언급 입니다.


답변

C ++에서

static const int foo = 42;

상수를 정의하고 사용하는 데 선호되는 방법입니다. 즉,

#define foo 42

유형 안전 시스템을 파괴하지 않기 때문입니다.


답변

모든 훌륭한 답변에 작은 세부 사항을 추가하고 싶습니다.

플러그인 (예 : CAD 시스템에서로드 할 DLL 또는 .so 라이브러리)을 작성하면 static 은 다음 과 같은 이름 충돌을 방지하는 생명의 은인입니다.

  1. CAD 시스템은 “const int foo = 42;”가있는 플러그인 A를로드합니다. 그것에.
  2. 시스템은 “const int foo = 23;”이있는 플러그인 B를로드합니다. 그것에.
  3. 결과적으로 플러그인 B는 foo에 42 값을 사용합니다. 플러그인 로더는 이미 외부 링크가있는 “foo”가 있음을 인식하기 때문입니다.

더 나쁜 점 : 3 단계는 컴파일러 최적화, 플러그인로드 메커니즘 등에 따라 다르게 작동 할 수 있습니다.

두 개의 플러그인에서 두 개의 도우미 함수 (같은 이름, 다른 동작)로이 문제가 한 번 발생했습니다. 정적으로 선언하면 문제가 해결되었습니다.