etc./StackOverFlow

C에서 "정적"은 무엇을 의미합니까?

청렴결백한 만능 재주꾼 2023. 4. 25. 10:56
반응형

질문자 :David


C 코드의 여러 위치에서 사용되는 static 이라는 단어를 본 적이 있습니다. 이것은 C#의 정적 함수/클래스와 같습니까(구현이 개체 간에 공유됨)?



  1. 함수 내부의 정적 변수는 호출 사이에 값을 유지합니다.
  2. 정적 전역 변수 또는 함수는 선언된 파일에서만 "볼 수" 있습니다.

(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에는 클래스가 없으므로 이 기능은 관련이 없습니다.


Eli Bendersky

여기에서 다루지 않은 용도가 하나 더 있는데, 이는 배열 유형 선언의 일부로 함수에 대한 인수로 사용하는 것입니다.

 int someFunction(char arg[static 10]) { ... }

이 컨텍스트에서 이것은 이 함수에 전달된 인수가 10개 이상의 요소를 포함하는 char 자세한 내용은 여기에서 내 질문을 참조하십시오.


dreamlax

짧은 대답 ... 그것은 달려 있습니다.

  1. 정적 정의 지역 변수는 함수 호출 사이에 값을 잃지 않습니다. 즉, 전역 변수이지만 해당 변수가 정의된 지역 함수로 범위가 지정됩니다.

  2. 정적 전역 변수는 정의된 C 파일 외부에서 볼 수 없습니다.

  3. 정적 함수는 정의된 C 파일 외부에서 볼 수 없습니다.


cmcginty

다중 파일 변수 범위 예

여기에서는 정적이 여러 파일에서 함수 정의의 범위에 어떻게 영향을 미치는지 설명합니다.

교류

 #include <stdio.h> /* Undefined behavior: already defined in main. Binutils 2.24 gives an error and refuses to link. https://stackoverflow.com/questions/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(""); }

메인.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; }

GitHub 업스트림 .

컴파일 및 실행:

 gcc -c ac -o ao gcc -c main.c -o main.o gcc -o main main.o ao

산출:

 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 의미한다고 말합니다.

객체 또는 함수에 대한 파일 범위 식별자 선언에 스토리지 클래스 지정자 static이 포함된 경우 식별자에 내부 연결이 있습니다.

그리고 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 최적화가 없을 때 심볼 테이블에 정적 변수를 유지하는 이유는 무엇입니까? 그들은 무엇이든 사용할 수 있습니까? 디버깅을 위한 것일 수도 있습니다.

또한보십시오

C++ 익명 네임스페이스

C++에서는 정적 대신 익명의 네임스페이스를 사용하고 싶을 수 있습니다. 이렇게 하면 비슷한 효과를 얻을 수 있지만 유형 정의가 더 숨겨집니다. 이름 없는/익명 네임스페이스 대 정적 함수


Ciro Santilli 新疆再教育营六四事件法轮功郝海东

때에 따라 다르지:

 int foo() { static int x; return ++x; }

함수는 1, 2, 3 등을 반환합니다. --- 변수가 스택에 없습니다.

교류:

 static int foo() { }

이는 이 함수가 이 파일에서만 범위를 갖는다는 것을 의미합니다. 따라서 ac와 bc는 서로 다른 foo() 가질 수 있으며 foo는 공유 객체에 노출되지 않습니다. 따라서 ac에 foo를 정의했다면 bc 나 다른 곳에서 접근할 수 없었습니다.

대부분의 C 라이브러리에서 모든 "개인" 기능은 정적이며 대부분의 "공용" 기능은 그렇지 않습니다.


Artyom

사람들은 C의 '정적'에는 두 가지 의미가 있다고 계속 말합니다. 나는 그것에 하나의 의미를 부여하는 그것을 보는 다른 방법을 제공합니다:

  • 항목에 '정적'을 적용하면 해당 항목이 두 가지 속성을 갖게 됩니다. (a) 현재 범위 밖에서는 보이지 않습니다. (b) 지속적이다.

그것이 두 가지 의미를 가지고 있는 것처럼 보이는 이유는 C에서 '정적'이 적용될 수 있는 모든 항목이 이미 이 두 속성 중 하나를 가지고 있기 때문에 특정 사용법이 다른 하나에만 관련되는 것처럼 보이기 때문입니다.

예를 들어, 변수를 고려하십시오. 함수 외부에서 선언된 변수는 이미 (데이터 세그먼트에서) 지속성을 가지고 있으므로 '정적'을 적용하면 현재 범위(컴파일 단위) 외부에서만 볼 수 없도록 만들 수 있습니다. 반대로, 함수 내부에 선언된 변수는 이미 현재 범위(함수) 외부에서 비가시성을 가지고 있으므로 '정적'을 적용하면 영구적으로만 만들 수 있습니다.

함수에 '정적'을 적용하는 것은 전역 변수에 적용하는 것과 같습니다. 코드는 반드시 영구적이므로(적어도 언어 내에서) 가시성만 변경할 수 있습니다.

참고: 이 주석은 C에만 적용됩니다. C++에서 클래스 메서드에 '정적'을 적용하면 키워드에 실제로 다른 의미가 부여됩니다. C99 배열 인수 확장의 경우와 유사합니다.


PMar

위키피디아에서:

C 프로그래밍 언어에서 static 은 전역 변수 및 함수와 함께 사용되어 해당 범위를 포함하는 파일로 설정합니다. 로컬 변수에서 static은 자동으로 할당된 메모리 대신 정적으로 할당된 메모리에 변수를 저장하는 데 사용됩니다. 언어가 두 유형의 메모리 구현을 지시하지는 않지만 정적으로 할당된 메모리는 일반적으로 컴파일 시간에 프로그램의 데이터 세그먼트에 예약되는 반면 자동 할당된 메모리는 일반적으로 일시적인 호출 스택으로 구현됩니다.


OscarRyz

static 은 다른 컨텍스트에서 다른 것을 의미합니다.

  1. C 함수에서 정적 변수를 선언할 수 있습니다. 이 변수는 함수에서만 볼 수 있지만 한 번만 초기화되고 값을 유지한다는 점에서 전역 변수처럼 동작합니다. foo() 를 호출할 때마다 증가하는 숫자를 인쇄합니다. 정적 변수는 한 번만 초기화됩니다.

     void foo () { static int i = 0; printf("%d", i); i++ }
  2. 정적의 또 다른 용도는 .c 파일에서 함수 또는 전역 변수를 구현하지만 해당 기호가 파일에 의해 생성된 .obj

     static void foo() { ... }

m-sharp

나는 오래된 질문에 대답하는 것을 싫어하지만 "C 프로그래밍 언어"의 섹션 A4.1에서 K&R이 설명하는 방법에 대해 언급한 사람은 아무도 없는 것 같습니다.

요컨대, 정적이라는 단어는 두 가지 의미로 사용됩니다.

  1. 정적은 두 가지 스토리지 클래스 중 하나입니다(다른 하나는 자동). 정적 개체는 호출 간에 값을 유지합니다. 모든 블록 외부에 선언된 객체는 항상 정적이며 자동으로 만들 수 없습니다.
  2. 그러나 static 키워드 (코드에서 키워드로 사용되는 것을 크게 강조)를 선언과 함께 사용하면 해당 개체에 내부 연결을 제공하므로 해당 번역 단위 내에서만 사용할 수 있습니다. 그러나 키워드가 함수에서 사용되면 객체의 스토리지 클래스가 변경됩니다(객체는 어쨌든 해당 함수 내에서만 볼 수 있음). static의 반대는 객체 외부 연결을 제공하는 extern

Peter Van Der Linden은 "전문가 C 프로그래밍"에서 다음 두 가지 의미를 제공합니다.

  • 함수 내에서 호출 간에 값을 유지합니다.
  • 함수 수준에서 이 파일에서만 볼 수 있습니다.

jigglypuff

정적 함수에서 변수를 선언하면 해당 값이 함수 호출 스택에 저장되지 않고 함수를 다시 호출할 때 계속 사용할 수 있습니다.

전역 변수를 static으로 선언하면 해당 범위는 선언한 파일 내로 제한됩니다. 이것은 전체 프로그램에서 읽고 수정할 수 있는 일반 전역보다 약간 더 안전합니다.


Jonathan Adelson

C에서 static은 사용 범위에 따라 두 가지 의미를 갖습니다. 전역 범위에서 개체가 파일 수준에서 선언되면 해당 개체는 해당 파일 내에서만 볼 수 있음을 의미합니다.

다른 범위에서는 특정 범위가 입력되는 다른 시간 사이에 값을 유지하는 개체를 선언합니다. 예를 들어 프로시저 내에서 int가 선언된 경우:

 void procedure(void) { static int i = 0; i++; }

'i'의 값은 프로시저에 대한 첫 번째 호출에서 0으로 초기화되고 이후에 프로시저가 호출될 때마다 값이 유지됩니다. 'i'가 인쇄되면 0, 1, 2, 3, ...의 시퀀스가 출력됩니다.


Gary

함수의 정적 변수는 해당 함수의 첫 번째 항목에서 초기화되고 호출이 완료된 후에도 유지된다는 점에 유의하는 것이 중요합니다. 재귀 함수의 경우 정적 변수는 한 번만 초기화되고 모든 재귀 호출과 함수 호출이 완료된 후에도 지속됩니다.

변수가 함수 외부에서 생성된 경우 프로그래머는 변수가 선언된 소스 파일에서만 변수를 사용할 수 있음을 의미합니다.


Starhowl

C의 정적 변수에는 프로그램의 수명이 있습니다.

함수에 정의된 경우 로컬 범위가 있습니다. 즉, 해당 함수 내에서만 액세스할 수 있습니다. 정적 변수의 값은 함수 호출 간에 유지됩니다.

예를 들어:

 void function() { static int var = 1; var++; printf("%d", var); } int main() { function(); // Call 1 function(); // Call 2 }

위의 프로그램에서 var 는 데이터 세그먼트에 저장됩니다. 수명은 전체 C 프로그램입니다.

함수 호출 1 이후에는 var 가 2가 되고, 함수 호출 2 이후에는 var 가 3이 됩니다.

var 값은 함수 호출 사이에 소멸되지 않습니다.

var 가 비정적 변수와 지역 변수 사이에 있으면 C 프로그램의 스택 세그먼트에 저장됩니다. 함수가 반환된 후 함수의 스택 프레임이 소멸되므로 var 값도 소멸됩니다.

초기화된 정적 변수는 C 프로그램의 데이터 세그먼트에 저장되고 초기화되지 않은 변수는 BSS 세그먼트에 저장됩니다.

정적에 대한 또 다른 정보: 변수가 전역이고 정적이면 C 프로그램의 수명이 있지만 파일 범위가 있습니다. 해당 파일에서만 볼 수 있습니다.

이것을 시도하려면:

파일1.c

 static int x; int main() { printf("Accessing in same file%d", x): }

파일2.c

 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에 대한 참조를 확인할 수 없기 때문에 링커 오류가 발생합니다.

참조:

  1. http://en.wikipedia.org/wiki/Translation_unit_(프로그래밍)
  2. http://en.wikipedia.org/wiki/Call_stack

Sahil Manchanda

mytest.c 파일에서 이것을 선언하는 경우:

 static int my_variable;

그러면 이 변수는 이 파일에서만 볼 수 있습니다. 변수는 다른 곳으로 내보낼 수 없습니다.

함수 내에서 선언하면 변수 값은 함수가 호출될 때마다 값을 유지합니다.

정적 함수는 파일 외부에서 내보낼 수 없습니다. 따라서 *.c 파일에서 함수와 변수를 정적으로 선언하면 숨겨집니다.


ant2009

정적 변수는 함수에서 사용할 수 있는 특수 변수로 호출 사이에 데이터를 저장하고 호출 사이에 데이터를 삭제하지 않습니다. 예를 들어:

 void func(void) { static int count; // If you don't declare its value, it is initialized with zero printf("%d, ", count); ++count; } int main(void) { while(true) { func(); } return 0; }

출력:

0, 1, 2, 3, 4, 5, ...


Yagel

정적 변수 값은 다른 함수 호출 간에 지속되며 해당 범위는 로컬 블록으로 제한됩니다. 정적 변수는 항상 값 0으로 초기화됩니다.


Jonathon

2가지 경우가 있습니다:

static 선언된 지역변수 : 스택이 아닌 데이터 세그먼트에 할당된다. 함수를 다시 호출할 때 해당 값이 유지됩니다.

(2) 전역 변수 또는 static 선언된 함수: 컴파일 단위 외부에서 볼 수 없습니다(즉, 링크하는 동안 심볼 테이블의 로컬 심볼).


Jonny Kong

정적 변수는 범위를 벗어난 후에도 값 을 유지하는 속성이 있습니다! 따라서 정적 변수는 이전 범위에서 이전 값을 유지하고 새 범위에서 다시 초기화되지 않습니다.

예를 들어 이것을 보십시오 - 정적 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은 static으로 선언되어 메모리에 남아 있기 때문에

전역 변수와 같은 정적 변수는 명시적으로 초기화되지 않은 경우 0으로 초기화됩니다. 예를 들어 아래 프로그램에서 x의 값은 0으로 인쇄되지만 y의 값은 쓰레기입니다. 자세한 내용은 이것을 참조하십시오.

 #include <stdio.h> int main() { static int x; int y; printf("%d \n %d", x, y); }

이것은 출력할 것입니다: 0 [some_garbage_value]

이것들은 초보자를 위해 위에서 설명하지 않은 주요 것들입니다!


era5tone

C 프로그래밍에서 static 은 수명과 가시성을 모두 제어하는 예약된 키워드입니다. 함수 내에서 변수를 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 을 실행하는 동안 count 변수를 파괴합니다.


Makdia Hussain

출처 : http:www.stackoverflow.com/questions/572547/what-does-static-mean-in-c

반응형