일부를 리팩토링 할 때 #defines
C ++ 헤더 파일에서 다음과 유사한 선언을 발견했습니다.
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
가없는 객체 는 암시 적으로 .static
extern
static
답변
파일 범위 변수 의 static
및 extern
태그는 다른 번역 단위 (예 : 기타 .c
또는 .cpp
파일) 에서 액세스 할 수 있는지 여부를 결정합니다 .
-
static
변수 내부 연결을 제공하여 다른 번역 단위에서 숨 깁니다. 그러나 내부 연결이있는 변수는 여러 번역 단위로 정의 할 수 있습니다. -
extern
변수 외부 연결을 제공하여 다른 번역 단위에서 볼 수 있도록합니다. 일반적으로 이것은 변수가 하나의 번역 단위에서만 정의되어야 함을 의미합니다.
기본값 ( static
또는을 지정하지 않은 경우 extern
)은 C와 C ++가 다른 영역 중 하나입니다.
-
C에서 파일 범위 변수는
extern
기본적으로 (외부 연결)입니다. C를 사용하는 경우VAL
isstatic
및ANOTHER_VAL
isextern
. -
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
답변
const
C ++의 변수에는 내부 연결이 있습니다. 따라서 사용하면 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 유형은 쉽게 인라인 될 수 없으므로 기본 유형의 특별한 경우가 됨)