태그 보관물: static

static

헤더 파일의 변수 선언-정적 여부? 리팩토링 할 때 #definesC ++ 헤더

일부를 리팩토링 할 때 #definesC ++ 헤더 파일에서 다음과 유사한 선언을 발견했습니다.

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

문제는 정전기가 어떤 차이를 만들까요? 고전적인 #ifndef HEADER #define HEADER #endif트릭 으로 인해 헤더를 여러 번 포함하는 것은 불가능합니다 (중요한 경우).

정적은 VAL헤더가 둘 이상의 소스 파일에 포함 된 경우 하나의 복사본 만 생성 된다는 것을 의미합니까 ?



답변

이는 포함 된 각 소스 파일에 대해 static하나의 복사본이 VAL생성된다는 것을 의미합니다. 그러나 여러 포함이 VAL링크 타임에 충돌하는 여러 정의로 이어지지 않음을 의미합니다 . C에서, static당신은 하나의 소스 파일 만 정의 VAL하고 다른 소스 파일은 그것을 선언 했는지 확인해야 합니다 extern. 일반적으로 소스 파일에서 (이니셜 라이저를 사용하여) 정의 extern하고 헤더 파일에 선언을 넣어이를 수행 합니다.

static 전역 수준의 변수는 포함을 통해 얻었 든 주 파일에 있었 든 자체 소스 파일에서만 볼 수 있습니다.


편집자 주 : C ++ 에서 선언에 nor 키워드 const가없는 객체 는 암시 적으로 .staticexternstatic


답변

파일 범위 변수 의 staticextern태그는 다른 번역 단위 (예 : 기타 .c또는 .cpp파일) 에서 액세스 할 수 있는지 여부를 결정합니다 .

  • static변수 내부 연결을 제공하여 다른 번역 단위에서 숨 깁니다. 그러나 내부 연결이있는 변수는 여러 번역 단위로 정의 할 수 있습니다.

  • extern변수 외부 연결을 제공하여 다른 번역 단위에서 볼 수 있도록합니다. 일반적으로 이것은 변수가 하나의 번역 단위에서만 정의되어야 함을 의미합니다.

기본값 ( static또는을 지정하지 않은 경우 extern)은 C와 C ++가 다른 영역 중 하나입니다.

  • C에서 파일 범위 변수는 extern기본적으로 (외부 연결)입니다. C를 사용하는 경우 VALis staticANOTHER_VALis extern.

  • C ++에서 파일 범위 변수는 static기본적으로 인 경우 (내부 연결) const이고 extern그렇지 않은 경우 기본적으로입니다. 당신이 사용하는 경우 C ++, 모두 VAL하고 ANOTHER_VAL있습니다 static.

C 사양 초안에서 :

6.2.2 식별자 연결 … -5- 함수에 대한 식별자 선언에 저장 클래스 지정자가 없으면 연결은 저장 클래스 지정자 extern으로 선언 된 것처럼 정확하게 결정됩니다. 객체에 대한 식별자 선언에 파일 범위가 있고 스토리지 클래스 지정자가없는 경우 해당 링크는 외부입니다.

C ++ 사양 초안에서 :

7.1.1-스토리지 클래스 지정자 [dcl.stc] … -6- 스토리지 클래스 지정자가없는 네임 스페이스 범위에서 선언 된 이름은 이전 선언으로 인해 내부 연결이없고 그렇지 않은 경우 외부 연결을 갖습니다. 선언 된 const. const로 선언되고 명시 적으로 선언되지 않은 extern 개체는 내부 연결이 있습니다.


답변

정적은 파일 당 하나의 사본을 얻는 것을 의미하지만 다른 사람들과 달리 그렇게하는 것이 완벽하게 합법적이라고 말했습니다. 작은 코드 샘플로 쉽게 테스트 할 수 있습니다.

test.h :

static int TEST = 0;
void test();

test1.cpp :

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp :

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

이것을 실행하면 다음과 같은 출력이 제공됩니다.

0x446020
0x446040


답변

constC ++의 변수에는 내부 연결이 있습니다. 따라서 사용하면 static효과가 없습니다.

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

이것이 C 프로그램이라면 i(외부 연결로 인해) ‘다중 정의’오류가 발생합니다 .


답변

이 수준의 코드에서 정적 선언은 변수가 현재 컴파일 단위에서만 볼 수 있음을 의미합니다. 이는 해당 모듈 내의 코드 만 해당 변수를 볼 수 있음을 의미합니다.

정적 변수를 선언하는 헤더 파일이 있고 해당 헤더가 여러 C / CPP 파일에 포함 된 경우 해당 변수는 해당 모듈에 대해 “로컬”이됩니다. 헤더가 포함 된 N 개의 장소에 대해 해당 변수의 N 개의 사본이 있습니다. 그들은 서로 전혀 관련이 없습니다. 이러한 소스 파일 내의 모든 코드는 해당 모듈 내에서 선언 된 변수 만 참조합니다.

이 특별한 경우에는 ‘static’키워드가 어떤 이점도 제공하지 않는 것 같습니다. 나는 뭔가를 놓치고 있을지도 모르지만 그것은 중요하지 않은 것 같다. 나는 전에 이와 같은 일을 본 적이 없다.

인라인의 경우이 경우 변수가 인라인 될 가능성이 있지만 이는 const로 선언 되었기 때문입니다. 컴파일러 모듈 정적 변수를 인라인 할 가능성이 더 높지만 상황과 컴파일되는 코드에 따라 다릅니다. 컴파일러가 ‘정적’을 인라인 할 것이라는 보장은 없습니다.


답변

C 책 (무료 온라인)에는 ‘정적’의 의미를 더 자세히 설명하는 연결에 대한 장이 있습니다 (정답은 이미 다른 의견에 나와 있음).
http://publications.gbdirect.co.uk/c_book /chapter4/linkage.html


답변

“정적이란 헤더가 둘 이상의 소스 파일에 포함 된 경우 VAL의 사본이 하나만 생성된다는 것을 의미합니까?”라는 질문에 답하기 위해 …

아니 . VAL은 항상 헤더를 포함하는 모든 파일에서 별도로 정의됩니다.

이 경우 C 및 C ++ 표준이 차이를 유발합니다.

C에서 파일 범위 변수는 기본적으로 extern입니다. C를 사용하는 경우 VAL은 정적이고 ANOTHER_VAL은 extern입니다.

최신 링커는 헤더가 다른 파일에 포함 된 경우 (동일한 전역 이름이 두 번 정의 됨) ANOTHER_VAL에 대해 불평 할 수 있으며 ANOTHER_VAL이 다른 파일에서 다른 값으로 초기화되면 분명히 불평 할 것입니다.

C ++에서 파일 범위 변수는 const 인 경우 기본적으로 정적이고 그렇지 않은 경우 기본적으로 extern입니다. C ++를 사용하는 경우 VAL과 ANOTHER_VAL은 모두 정적입니다.

또한 두 변수가 모두 const로 지정된다는 사실을 고려해야합니다. 이상적으로 컴파일러는 항상 이러한 변수를 인라인하고 저장소를 포함하지 않도록 선택합니다. 스토리지를 할당 할 수있는 이유는 여러 가지가 있습니다. 내가 생각할 수있는 것들 …

  • 디버그 옵션
  • 파일에서 가져온 주소
  • 컴파일러는 항상 저장소를 할당합니다 (복잡한 const 유형은 쉽게 인라인 될 수 없으므로 기본 유형의 특별한 경우가 됨)