[c] C의 정적 함수

C에서 함수를 정적으로 만드는 요점은 무엇입니까?



답변

함수를 만들면 static다른 번역 단위에서 숨겨져 캡슐화를 제공하는 데 도움이됩니다 .

helper_file.c

int f1(int);        /* prototype */
static int f2(int); /* prototype */

int f1(int foo) {
    return f2(foo); /* ok, f2 is in the same translation unit */
                    /* (basically same .c file) as f1         */
}

int f2(int foo) {
    return 42 + foo;
}

main.c :

int f1(int); /* prototype */
int f2(int); /* prototype */

int main(void) {
    f1(10); /* ok, f1 is visible to the linker */
    f2(12); /* nope, f2 is not visible to the linker */
    return 0;
}


답변

pmg 은 캡슐화에 대해 자리 잡고있다; 함수를 다른 변환 단위 (또는 그로 인해 ) 에서 숨기는 것 외에도 함수를 만들면 static컴파일러 최적화가있을 때 성능 이점을 얻을 수 있습니다.

static코드가 주소에 대한 포인터를 사용하지 않는 한 현재 변환 단위 외부 에서는 함수를 호출 할 수 없으므로 컴파일러는 모든 호출 지점을 제어합니다.

즉, 비표준 ABI를 자유롭게 사용하거나 완전히 인라인하거나 외부 연결 기능으로는 불가능한 다른 최적화를 수행 할 수 있습니다.


답변

staticC 의 키워드는 함수가 해당 파일에만 존재하도록 컴파일 된 파일 (.h와 반대로 .c)에서 사용됩니다.

일반적으로 함수를 만들 때 컴파일러는 링커가 함수 호출을 해당 함수에 연결하는 데 사용할 수있는 cruft를 생성합니다. static 키워드를 사용하면 링커에 의존하지 않고 수행 할 수 있기 때문에 동일한 파일 내의 다른 함수가이 함수를 호출 할 수 있지만 링커에는 다른 파일이 함수에 액세스하도록하는 정보가 없습니다.


답변

위의 게시물을 보면 한 가지 세부 사항을 지적하고 싶습니다.

기본 파일 ( “main.c”)이 다음과 같다고 가정합니다.

#include "header.h"

int main(void) {
    FunctionInHeader();
}

이제 세 가지 경우를 고려하십시오.

  • 사례 1 : 헤더 파일 ( “header.h”)은 다음과 같습니다.

    #include <stdio.h>
    
    static void FunctionInHeader();
    
    void FunctionInHeader() {
        printf("Calling function inside header\n");
    }

    그런 다음 Linux에서 다음 명령을 수행하십시오.

    gcc main.c header.h -o main

    성공할 것이다 ! 다음 중 하나를 실행하면

    ./main

    출력은

    헤더 내부의 함수 호출

    정적 함수가 인쇄해야하는 것은 다음과 같습니다.

  • 사례 2 : 헤더 파일 ( “header.h”)은 다음과 같습니다.

    static void FunctionInHeader();     

    또한 “header.c”파일이 하나 더 있습니다.

    #include <stdio.h>
    
    #include "header.h"
    
    void FunctionInHeader() {
        printf("Calling function inside header\n");
    }

    그런 다음 다음 명령

    gcc main.c header.h header.c -o main

    오류가 발생합니다.

  • 사례 3 :

    헤더 파일 ( “header.h”)이 다음을 제외하고 사례 2와 유사합니다.

    void FunctionInHeader(); // keyword static removed

    그런 다음 2와 동일한 명령이 성공하고 ./main을 추가로 실행하면 예상 결과가 나타납니다.

따라서이 테스트 (Acer x86 컴퓨터, Ubuntu OS에서 실행)에서 나는

static 키워드는 함수가 정의 된 위치가 아닌 다른 * .c 파일에서 함수가 호출되지 않도록합니다.

내가 틀렸다면 나를 바로 잡으십시오.


답변

C 프로그래머는 Java 및 C ++에서 공용 및 개인용 선언을 사용하는 것처럼 정적 속성을 사용하여 모듈 내에서 변수 및 함수 선언을 숨 깁니다. C 소스 파일은 모듈의 역할을합니다. 정적 속성으로 선언 된 모든 글로벌 변수 또는 함수는 해당 모듈 전용입니다. 마찬가지로 정적 속성없이 선언 된 전역 변수 또는 함수는 공용이며 다른 모듈에서 액세스 할 수 있습니다. 가능하면 정적 속성으로 변수와 함수를 보호하는 것이 좋습니다.


답변

pmg의 답변은 매우 설득력이 있습니다. 정적 선언이 객체 수준에서 어떻게 작동하는지 알고 싶다면 아래 정보가 흥미로울 수 있습니다. pmg가 작성한 동일한 프로그램을 재사용하고 .so (공유 객체) 파일로 컴파일러

다음 내용은 .so 파일을 사람이 읽을 수있는 것으로 덤프 한 후입니다.

0000000000000675 f1 : f1 함수의 주소

000000000000068c f2 : f2 (staticc) 함수의 주소

함수 주소의 차이에 주목하십시오. 다른 주소로 선언 된 함수의 경우 f2가 멀리 또는 객체 파일의 다른 세그먼트에 있다는 것을 잘 알 수 있습니다.

링커는 PLT (Procedure linkage table) 및 GOT (Global offsets table)이라는 것을 사용하여에 액세스 할 수있는 심볼을 이해합니다.

이제 GOT와 PLT는 모든 주소를 마술처럼 묶고 동적 섹션에는 링커가 볼 수있는 모든 기능에 대한 정보가 들어 있다고 생각합니다.

.so 파일의 동적 섹션을 덤프하면 많은 항목이 있지만 f1f2 함수 에만 관심이 있습니다.

동적 섹션은 주소 0000000000000675 에서 f1 기능에 대한 항목 만 보유하고 f2 에는 없습니다 .

숫자 : 값 크기 유형 바인드 비스 Ndx 이름

 9: 0000000000000675    23 FUNC    GLOBAL DEFAULT   11 f1

그리고 그게 다야 !. 이것으로부터 링커는 f2 함수가 .so 파일의 동적 섹션에 없기 때문에 f2 함수 를 찾는 데 실패 할 것 입니다.


답변

일부 함수에 대한 액세스를 제한해야하는 경우 함수를 정의하고 선언하는 동안 static 키워드를 사용합니다.

            /* file ab.c */
static void function1(void)
{
  puts("function1 called");
}
And store the following code in another file ab1.c

/* file ab1.c  */
int main(void)
{
 function1();
  getchar();
  return 0;
}
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */