[c] C의 “정적”기능은 무엇입니까?

문제는 일반에 관한 것이었다 기능이 아닌 static 의견에 명시된 바와 같이.

static변수가 무엇인지 이해 하지만 static함수 는 무엇 입니까?

그리고 왜 함수를 선언하면 (WITHOUT ) void print_matrix이라고 말하고 a.cinclude- 함께 -내가 그것을 선언 하면 컴파일하면 컴파일됩니까?a.h"a.c""print_matrix@@....) already defined in a.obj"static void print_matrix

업데이트 일을 정리하는 것만으로 .c도 많은 사람들이 지적한 것처럼 포함 이 나쁘다는 것을 알고 있습니다. 난 그냥 일시적으로 빈 공간에 어떻게 main.c내가 적절한으로하는 방법 그룹에 모든 기능의 더 나은 아이디어 때까지 .h.c파일을. 일시적인 빠른 솔루션입니다.



답변

static함수는 동일한 파일 (보다 정확하게 동일한 변환 단위 )의 다른 함수에서만 볼 수있는 함수입니다 .

편집 : 생각하는 사람들을 위해, 질문의 저자는 ‘클래스 방법’을 의미한다고 생각합니다. 질문에 태그가 붙어 있기 때문에 C그는 평범한 오래된 C 함수를 의미합니다. (C ++ / Java / …) 클래스 메소드의 static경우 클래스 자체에서이 메소드를 호출 할 수 있으며 해당 클래스의 인스턴스는 필요하지 않습니다.


답변

C의 정적 함수와 C ++의 정적 멤버 함수에는 큰 차이가 있습니다. C에서 정적 함수는 변환 단위 (컴파일 된 오브젝트 파일) 외부에서 볼 수 없습니다. 다시 말해, 함수를 정적으로 만들면 범위가 제한됩니다. 정적 함수는 * .c 파일에 대해 “비공개”인 것으로 생각할 수 있습니다 (엄격히 정확하지는 않지만).

C ++에서 “정적”은 멤버 함수 및 클래스의 데이터 멤버에도 적용 할 수 있습니다. 정적 데이터 멤버는 “클래스 변수”라고도하며 비 정적 데이터 멤버는 “인스턴스 변수”입니다. 이것이 스몰 토크 용어입니다. 이는 클래스의 모든 객체가 공유하는 정적 데이터 멤버의 사본이 하나만있는 반면 각 객체에는 비 정적 데이터 멤버의 고유 한 사본이 있습니다. 따라서 정적 데이터 멤버는 기본적으로 전역 변수, 즉 클래스 멤버입니다.

비 정적 멤버 함수는 정적 및 비 정적 클래스의 모든 데이터 멤버에 액세스 할 수 있습니다. 정적 멤버 함수는 정적 데이터 멤버에서만 작동 할 수 있습니다.

이것을 생각하는 한 가지 방법은 C ++ 정적 데이터 멤버와 정적 멤버 함수가 객체가 아니라 전체 클래스에 속한다는 것입니다.


답변

C ++의 함수에서 static 키워드는 두 가지 용도로 사용됩니다.

첫 번째는 함수가 내부 연결이있는 것으로 표시하여 다른 변환 단위에서 참조 할 수 없도록하는 것입니다. 이 사용법은 C ++에서 더 이상 사용되지 않습니다. 이름없는 네임 스페이스가이 사용법에 선호됩니다.

// inside some .cpp file:

static void foo();    // old "C" way of having internal linkage

// C++ way:
namespace
{
   void this_function_has_internal_linkage()
   {
      // ...
   }
}

두 번째 사용법은 클래스와 관련이 있습니다. 클래스에 정적 멤버 함수가있는 경우 함수는 클래스의 멤버이며 다른 멤버에 대한 일반적인 액세스 권한이 있지만 특정 객체를 통해 호출 할 필요는 없습니다. 다시 말해, 그 함수 내부에는 “this”포인터가 없습니다.


답변

실행 가능한 최소 다중 파일 범위 예

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

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
 */
/*void f() { puts("a f"); }*/

/* OK: only declared, not defined. Will use the one in main. */
void f(void);

/* OK: only visible to this file. */
static void sf() { puts("a sf"); }

void a() {
    f();
    sf();
}

main.c

#include <stdio.h>

void a(void);        

void f() { puts("main f"); }

static void sf() { puts("main sf"); }

void m() {
    f();
    sf();
}

int main() {
    m();
    a();
    return 0;
}

GitHub의 상류 .

컴파일하고 실행하십시오.

gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main

산출:

main f
main sf
main f
a sf

해석

  • sf각 파일마다 하나씩 두 개의 개별 기능이 있습니다.
  • 단일 공유 기능이 있습니다 f

평소와 같이 범위가 작을수록 좋습니다. 가능하면 항상 함수를 선언하십시오 static.

C 프로그래밍에서 파일은 종종 “클래스”를 나타내는 데 사용되며 static함수는 클래스의 “비공개”메소드를 나타냅니다.

일반적인 C 패턴은 this구조체를 첫 번째 “메서드”인수로 전달하는 것인데, 기본적으로 C ++이 수행하는 작업입니다.

그것에 대해 말하는 표준

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 f() { return 0; }
static int sf() { return 0; }

다음과 같이 심볼 테이블을 분해하십시오.

readelf -s main.o

출력에는 다음이 포함됩니다.

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 000000000000000b    11 FUNC    LOCAL  DEFAULT    1 sf
  9: 0000000000000000    11 FUNC    GLOBAL DEFAULT    1 f

바인딩은 그들 사이의 유일한 중요한 차이점입니다. 섹션에 Value대한 오프셋 일 뿐이 .bss므로 차이가있을 것으로 예상합니다.

STB_LOCALhttp://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html 의 ELF 사양에 설명되어 있습니다 .

STB_LOCAL 로컬 심볼은 해당 정의를 포함하는 오브젝트 파일 외부에 표시되지 않습니다. 동일한 이름의 로컬 기호가 서로 방해하지 않고 여러 파일에 존재할 수 있습니다

표현하기에 완벽한 선택 static입니다.

정적이없는 함수는 STB_GLOBAL이며 사양은 다음과 같습니다.

링크 편집기가 재배치 가능한 여러 오브젝트 파일을 결합 할 때 동일한 이름을 가진 STB_GLOBAL 기호의 다중 정의를 허용하지 않습니다.

이는 여러 비 정적 정의의 링크 오류와 일치합니다.

로 최적화를 크랭크 -O3하면 sf심볼이 심볼 테이블에서 완전히 제거됩니다. 어쨌든 외부에서는 사용할 수 없습니다. TODO 최적화가 없을 때 심볼 테이블에 정적 함수를 유지하는 이유는 무엇입니까? 그들은 무엇이든 사용할 수 있습니까?

또한보십시오

C ++ 익명 네임 스페이스

C ++에서는 정적 대신 익명 네임 스페이스를 사용하여 비슷한 효과를 얻을 수 있지만 유형 정의를 숨 깁니다. 이름이없는 / 익명 네임 스페이스와 정적 함수


답변

다음은 일반 C 함수에 관한 것입니다. C ++ 클래스에서 수정 자 ‘정적’은 다른 의미를 갖습니다.

파일이 하나 뿐인 경우이 수정자는 아무런 차이가 없습니다. 파일이 여러 개인 대규모 프로젝트에서는 차이점이 있습니다.

C에서는 모든 “모듈”(sample.c와 sample.h의 조합)이 독립적으로 컴파일 된 후 컴파일 된 모든 객체 파일 (sample.o)이 링커에 의해 실행 파일에 함께 연결됩니다.

기본 파일에 포함 된 여러 파일이 있고 그 중 두 개는 편의상 내부에서만 사용되는 기능을 가지고 있다고 가정 해 봅시다 add(int a, b). 컴파일러는 두 모듈에 대한 객체 파일을 쉽게 만들 수 있지만 링커는 오류를 발생시킵니다. 동일한 이름을 가진 두 개의 함수를 찾고 어떤 함수를 사용해야하는지 알지 못합니다 (링크가없는 경우에도 다른 곳에서 사용되지 않고 자체 파일로 사용되기 때문에).

이것이 바로 내부 정적 함수 인이 함수를 만드는 이유입니다. 이 경우 컴파일러는 링커에 대해 일반적인 “이 링크를 연결할 수 있습니다”플래그를 만들지 않으므로 링커에서이 기능을 볼 수 없으며 오류가 발생하지 않습니다.


답변

첫째 : 일반적으로 .cpp다른 파일에 파일 을 포함시키는 것은 좋지 않습니다. 다음 과 같은 문제가 발생합니다. 🙂 일반적인 방법은 별도의 컴파일 단위를 만들고 포함 된 파일의 헤더 파일을 추가하는 것입니다.

둘째 :

C ++에는 혼란스러운 용어가 있습니다. 댓글에서 지적 할 때까지 그것에 대해 알지 못했습니다.

a) static functions-C에서 상속되었으며 여기에서 말하는 내용. 수업 외 정적 함수 는 현재 컴파일 단위 외부에서는 보이지 않으므로 a.obj에는 복사본이 있고 다른 코드에는 독립적 인 복사본이 있습니다. (여러 코드 사본으로 최종 실행 파일을 블로 팅).

b) static member function-정적 메소드 인 Object Orientation 용어 . 수업 안에 살고 있습니다. 이것을 객체 인스턴스가 아닌 클래스로 호출합니다.

이 두 가지 정적 함수 정의는 완전히 다릅니다. 조심하십시오-여기에 용이 있습니다.


답변

정적 함수 정의는이 기호를 내부로 표시합니다. 따라서 외부에서 링크하는 것은 보이지 않지만 동일한 컴파일 단위, 일반적으로 동일한 파일의 함수에만 표시됩니다.