static
C 코드의 다른 곳에서 사용되는 단어를 보았습니다 . 이것은 C #의 정적 함수 / 클래스와 비슷합니까 (구현이 객체간에 공유되는 경우)?
static
C 코드의 다른 곳에서 사용되는 단어를 보았습니다 . 이것은 C #의 정적 함수 / 클래스와 비슷합니까 (구현이 객체간에 공유되는 경우)?
답변:
초보자라면 (1)이 더 많은 주제입니다.
#include <stdio.h>
void foo()
{
int a = 10;
static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d\n", a, sa);
}
int main()
{
int i;
for (i = 0; i < 10; ++i)
foo();
}
인쇄합니다 :
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60
이것은 함수가 호출간에 상태를 유지해야하고 전역 변수를 사용하지 않으려는 경우에 유용합니다. 그러나이 기능은 매우 드물게 사용해야합니다. 코드가 스레드로부터 안전하지 않고 이해하기 어렵습니다.
(2) "액세스 제어"기능으로 널리 사용됩니다. 일부 기능을 구현하는 .c 파일이있는 경우 일반적으로 일부 "공개"기능 만 사용자에게 노출합니다. static
사용자가 액세스 할 수 없도록 나머지 기능을 수행해야 합니다. 이것은 캡슐화, 좋은 습관입니다.
인용 위키 백과 :
C 프로그래밍 언어에서 static은 전역 변수 및 함수와 함께 사용되어 해당 범위를 포함 파일로 설정합니다. 로컬 변수에서 static은 자동 할당 된 메모리 대신 정적 할당 된 메모리에 변수를 저장하는 데 사용됩니다. 언어가 두 가지 유형의 메모리 구현을 지시하지는 않지만 정적으로 할당 된 메모리는 일반적으로 컴파일 타임에 프로그램의 데이터 세그먼트에 예약되며 자동 할당 된 메모리는 일반적으로 임시 호출 스택으로 구현됩니다.
그리고 두 번째 질문에 대답하기 위해 C #과 다릅니다.
그러나 C ++에서는 static
클래스 속성 (같은 클래스의 모든 객체간에 공유) 및 메소드를 정의하는 데에도 사용됩니다. C에는 클래스가 없으므로이 기능은 관련이 없습니다.
.c
의 헤더 파일 이 될 수 있지만 악마는 항상 일반적인 것이 아닙니다 .
여기에서 다루지 않은 용도가 하나 더 있으며, 이는 함수에 대한 인수로 배열 유형 선언의 일부입니다.
int someFunction(char arg[static 10])
{
...
}
이와 관련하여이 함수에 전달 된 인수는 char
10 개 이상의 요소가 포함 된 유형의 배열이어야 함을 지정 합니다. 자세한 내용은 내 질문을 참조하십시오 여기 하십시오 .
arg[0]
을 통해이 arg[9]
(또한 함수는 NULL 포인터를 허용하지 않는 것을 의미한다) 값을 가질 것이다. 컴파일러는이 정보를 어떻게 든 최적화를 위해 사용할 수 있으며 정적 분석기는이 정보를 사용하여 함수에 널 포인터 (또는 지정된 것보다 적은 수의 요소를 가진 배열이 제공되지 않는 경우)가 제공되지 않도록 할 수 있습니다.
static
C99에 주어진 새로운 오버로드 의미 입니다. 10 년 반이 넘었지만 모든 컴파일러 작성자가 모든 C99 기능을 수용 한 것은 아니므로 C99는 대체로 알려지지 않았습니다.
int arr[n];
, 다음입니다 VLA (가변 길이 배열) C99에서 추가되었다. 그게 무슨 뜻입니까?
짧은 대답 ... 그것은 달려 있습니다.
정적 정의 로컬 변수는 함수 호출간에 값을 잃지 않습니다. 다시 말해, 그것들은 전역 변수이지만 그것들이 정의 된 지역 함수의 범위를 갖습니다.
정적 전역 변수는 정의 된 C 파일 외부에서 볼 수 없습니다.
정적 함수는 정의 된 C 파일 외부에서 볼 수 없습니다.
private
C 에는 없지만 , 비유는 좋다 : static은 주어진 파일에 "개인"을 만든다. 그리고 C의 파일은 종종 C ++의 클래스에 매핑됩니다.
다중 파일 변수 범위 예
여기서 정적이 여러 파일에서 함수 정의 범위에 미치는 영향을 설명합니다.
ac
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */
/*int i;*/
/* OK: extern. Will use the one in main. */
extern int i;
/* OK: only visible to this file. */
static int si = 0;
void a() {
i++;
si++;
puts("a()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
main.c
#include <stdio.h>
int i = 0;
static int si = 0;
void a();
void m() {
i++;
si++;
puts("m()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
int main() {
m();
m();
a();
a();
return 0;
}
컴파일하고 실행하십시오.
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
산출:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
해석
si
파일마다 하나씩 두 개의 개별 변수가 있습니다.i
평소와 같이 범위가 작을수록 좋습니다. 가능하면 항상 변수를 선언하십시오 static
.
C 프로그래밍에서 파일은 종종 "클래스"를 나타내는 데 사용되며 static
변수는 클래스의 전용 정적 멤버를 나타냅니다.
그것에 대해 말하는 표준
C99 N1256 draft 6.7.1 "스토리지 클래스 지정자"는 "스토리지 클래스 지정자"라고 말합니다 static
.
6.2.2 / 3 "식별자의 연결"은 다음을 static
의미합니다 internal linkage
.
객체 또는 함수에 대한 파일 범위 식별자 선언에 스토리지 클래스 지정자 정적이 포함되어 있으면 식별자에 내부 연결이 있습니다.
그리고 6.2.2 / 2는 internal linkage
우리 예제에서와 같이 동작 한다고 말합니다 :
전체 프로그램을 구성하는 변환 단위 및 라이브러리 세트에서 외부 링크가있는 특정 식별자의 각 선언은 동일한 객체 또는 함수를 나타냅니다. 하나의 변환 단위 내에서 내부 연결이있는 식별자의 각 선언은 동일한 객체 또는 함수를 나타냅니다.
여기서 "번역 단위는 전처리 후 소스 파일입니다.
GCC가 ELF (Linux)를 위해 어떻게 구현합니까?
와 더불어 STB_LOCAL
바인딩.
우리가 컴파일하면 :
int i = 0;
static int si = 0;
다음과 같이 심볼 테이블을 분해하십시오.
readelf -s main.o
출력에는 다음이 포함됩니다.
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
바인딩은 그들 사이의 유일한 중요한 차이점입니다. 섹션에 Value
대한 오프셋 일 뿐이 .bss
므로 차이가있을 것으로 예상합니다.
STB_LOCAL
http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html 의 ELF 사양에 설명되어 있습니다 .
STB_LOCAL 로컬 심볼은 해당 정의를 포함하는 오브젝트 파일 외부에 표시되지 않습니다. 동일한 이름의 로컬 기호가 서로 방해하지 않고 여러 파일에 존재할 수 있습니다
표현하기에 완벽한 선택 static
입니다.
정적 변수가없는 변수 STB_GLOBAL
는 사양이며 다음과 같이 말합니다.
링크 편집기가 재배치 가능한 여러 오브젝트 파일을 결합 할 때 동일한 이름을 가진 STB_GLOBAL 기호의 다중 정의를 허용하지 않습니다.
이는 여러 비 정적 정의의 링크 오류와 일치합니다.
로 최적화를 크랭크 -O3
하면 si
심볼이 심볼 테이블에서 완전히 제거됩니다. 어쨌든 외부에서는 사용할 수 없습니다. TODO 최적화가 없을 때 왜 심볼 테이블에 정적 변수를 유지합니까? 그들은 무엇이든 사용할 수 있습니까? 아마도 디버깅을 위해.
또한보십시오
static
기능 과 유사 함 : https://stackoverflow.com/a/30319812/895245static
에 extern
"반대"않는, 어떻게 소스 파일 간의 공유 변수에 통근 사용합니까?C ++ 익명 네임 스페이스
C ++에서는 정적 대신 익명 네임 스페이스를 사용하여 비슷한 효과를 얻을 수 있지만 유형 정의를 숨 깁니다. 이름이없는 / 익명 네임 스페이스와 정적 함수
때에 따라 다르지:
int foo()
{
static int x;
return ++x;
}
이 함수는 1, 2, 3 등을 반환합니다. --- 변수가 스택에 없습니다.
static int foo()
{
}
이 함수는이 파일에서만 범위를 갖습니다. 따라서 ac와 bc는 서로 다른 foo()
s를 가질 수 있으며 foo는 공유 객체에 노출되지 않습니다. 따라서 AC에서 foo를 정의 b.c
하면 다른 곳 에서 또는 다른 곳에서 액세스 할 수 없습니다 .
대부분의 C 라이브러리에서 모든 "비공개"기능은 정적이며 대부분의 "공용"기능은 아닙니다.
사람들은 C에서 '정적'은 두 가지 의미가 있다고 계속 말합니다. 나는 그것을 의미하는 대체 방법을 제공합니다.
그것이 두 가지 의미를 갖는 것처럼 보이는 이유는 C에서 '정적'이 적용될 수있는 모든 항목이 이미이 두 가지 속성 중 하나를 가지고 있기 때문에 특정 용도가 다른 것만 포함하는 것처럼 보입니다 .
예를 들어 변수를 고려하십시오. 함수 외부에서 선언 된 변수는 이미 데이터 세그먼트에서 지속성을 가지고 있으므로 '정적'을 적용하면 현재 범위 (컴파일 단위) 외부에서만 보이지 않습니다. 반대로, 함수 내부에 선언 된 변수는 이미 현재 범위 (함수) 외부에 표시되지 않으므로 '정적'을 적용하면 지속될 수 있습니다.
함수에 '정적'을 적용하는 것은 전역 변수에 적용하는 것과 같습니다. 코드는 반드시 영구적이어야합니다 (적어도 언어 내에서). 따라서 가시성 만 변경할 수 있습니다.
참고 :이 주석은 C에만 적용됩니다. C ++에서 클래스 메소드에 '정적'을 적용하면 키워드에 다른 의미가 부여됩니다. C99 배열 인수 확장의 경우와 유사합니다.
static
제공합니다 .
static
다른 맥락에서 다른 것을 의미합니다.
C 함수에서 정적 변수를 선언 할 수 있습니다. 이 변수는 함수에서만 볼 수 있지만 한 번만 초기화되고 값을 유지한다는 점에서 전역처럼 동작합니다. 이 예에서는 전화 foo()
할 때마다 번호가 증가합니다. 정적 변수는 한 번만 초기화됩니다.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
static의 또 다른 사용은 .c 파일에서 함수 또는 전역 변수를 구현하지만 파일에서 .obj
생성 된 심볼 외부에서 심볼을 표시하지 않으려 는 경우입니다. 예 :
static void foo() { ... }
나는 오래된 질문에 대답하기는 싫지만 "C 프로그래밍 언어"의 A4.1 섹션에서 K & R이 어떻게 설명하는지 언급 한 사람은 없다고 생각합니다.
간단히 말해서 static이라는 단어는 두 가지 의미 로 사용됩니다 .
static
키워드 (코드에서 키워드로 사용되는 키워드에 중점을 두는 키워드)를 선언과 함께 사용하면 해당 개체 내부 연결을 제공하므로 해당 번역 단위 내에서만 사용할 수 있습니다. 그러나 키워드가 함수에 사용되면 객체의 스토리지 클래스가 변경됩니다 (오브젝트는 해당 함수 내에서만 볼 수 있음). static과 반대되는 extern
키워드는 객체에 외부 연결을 제공합니다.Peter Van Der Linden은 "전문가 C 프로그래밍"에서 다음 두 가지 의미를 제공합니다.
register
&
register
C에서 static은 사용 범위에 따라 두 가지 의미를 갖습니다. 전역 범위에서 파일 수준에서 개체를 선언하면 해당 개체는 해당 파일 내에서만 볼 수 있습니다.
다른 범위에서는 특정 범위를 입력 한 다른 시간 사이에 값을 유지하는 객체를 선언합니다. 예를 들어, int가 프로 시저 내에서 분리되는 경우 :
void procedure(void)
{
static int i = 0;
i++;
}
프로 시저를 처음 호출 할 때 'i'값이 0으로 초기화되고, 프로 시저가 호출 될 때마다 값이 유지됩니다. 'i'가 인쇄되면 0, 1, 2, 3, ...의 시퀀스를 출력합니다.
C의 정적 변수는 프로그램 수명이 있습니다.
함수에 정의 된 경우 로컬 범위를 가지므로 해당 함수 내에서만 액세스 할 수 있습니다. 정적 변수의 값은 함수 호출간에 유지됩니다.
예를 들면 다음과 같습니다.
void function()
{
static int var = 1;
var++;
printf("%d", var);
}
int main()
{
function(); // Call 1
function(); // Call 2
}
위 프로그램에서 var
에서 데이터 세그먼트에 저장됩니다. 수명은 전체 C 프로그램입니다.
기능 호출 1 var
후에 2 var
가됩니다. 기능 호출 2 후에 3이됩니다.
의 가치 var
함수 호출 사이 소멸되지 않습니다.
var
정적이 아닌 변수와 로컬 변수 사이에 있으면 C 프로그램의 스택 세그먼트에 저장됩니다. 함수가 반환 된 후 함수의 스택 프레임이 소멸되므로var
도 소멸됩니다.
초기화 된 정적 변수는 C 프로그램의 데이터 세그먼트에 저장되고 초기화되지 않은 변수는 BSS 세그먼트에 저장됩니다.
정적에 대한 또 다른 정보 : 변수가 전역 및 정적 인 경우 C 프로그램의 수명은 있지만 파일 범위가 있습니다. 해당 파일에서만 볼 수 있습니다.
이것을 시도하려면 :
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
extern int x;
func()
{
printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
}
run gcc -c file1.c
gcc -c file2.c
이제 다음을 사용하여 연결하십시오.
gcc -o output file1.o file2.o
x에 file1.c의 파일 범위가 있고 링커가 file2.c에 사용 된 변수 x에 대한 참조를 확인할 수 없으므로 링커 오류가 발생합니다.
참고 문헌 :
static int var = 1;
매번 값을 다시 1로 변경 하지 않는 이유는 무엇입니까?
정적 변수는 함수에서 사용할 수있는 특수 변수이며 호출간에 데이터를 저장하며 호출간에 삭제하지 않습니다. 예를 들면 다음과 같습니다.
void func(){
static int count; // If you don't declare its value, the value automatically initializes to zero
printf("%d, ", count);
++count;
}
void main(){
while(true){
func();
}
}
출력 :
0, 1, 2, 3, 4, 5, ...
printf("%d, ", count); count++;
`printf ( "% d,", count ++)로 바꿀 수 있습니다 (중요하지는 않습니다 : P).
정적 변수는 범위를 벗어난 후에도 값 을 유지 하는 속성을 갖습니다 ! 따라서 정적 변수는 이전 범위에서 이전 값을 유지하고 새 범위에서 다시 초기화되지 않습니다.
예를 들어보십시오-정적 int 변수는 프로그램이 실행되는 동안 메모리에 남아 있습니다. 변수가 선언 된 함수 호출이 끝나면 일반 또는 자동 변수가 삭제됩니다.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
출력됩니다 : 1 2
정적로 선언 된대로 1이 메모리에 머무르면서
전역 변수와 같은 정적 변수는 명시 적으로 초기화되지 않은 경우 0으로 초기화됩니다. 예를 들어 아래 프로그램에서 x 값은 0으로 인쇄되는 반면 y 값은 가비지입니다. 자세한 내용은 이것을 참조하십시오.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
출력됩니다 : 0 [some_garbage_value]
이들은 내가 초보자를 위해 위에서 설명하지 않은 주요 것들입니다!
C 프로그래밍에서 static
수명과 가시성을 모두 제어하는 예약 키워드입니다. 함수 내에서 변수를 정적으로 선언하면 해당 함수 전체에서만 볼 수 있습니다. 이 사용법에서이 정적 변수의 수명은 함수 호출시 시작되며 해당 함수 실행 후 소멸됩니다. 다음 예제를 볼 수 있습니다.
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
위의 프로그램은 우리에게 다음과 같은 결과를 줄 것입니다.
First Counter Output = 1
Second Counter Output = 1
함수를 호출하자마자을 초기화하기 때문 count = 0
입니다. 그리고 우리가 counterFunction
그것을 실행하는 동안 카운트 변수를 파괴합니다.