programing

C의 함수 포인터 - 성질 및 용도

iphone6s 2023. 10. 24. 20:15
반응형

C의 함수 포인터 - 성질 및 용도

방금 여기서 두 가지 더 궁금해지는 흥미로운 질문을 읽었습니다.

  1. 개념에 의해 함수의 고유성이 서로 다른 이름으로 보장되는 것을 감안할 때, 함수 포인터를 비교해야 하는 이유는 무엇입니까?
  2. 컴파일러는 함수 포인터를 특수 포인터로 보십니까?제 말은 그들이 마치, 예를 들어, 그들이, 예를 들어,void *아니면 더 풍부한 정보(반환 유형, 인수 수 및 인수 유형 등)를 보유하고 있습니까?

함수 포인터를 비교해야 하는 이유는 무엇입니까?다음은 한 가지 예입니다.

#include <stdbool.h>

/*
 * Register a function to be executed on event. A function may only be registered once.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful registration, false if the function is already registered.
 */
bool register_function_for_event(void (*arg)(void));

/*
 * Un-register a function previously registered for execution on event.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful un-registration, false if the function was not registered.
 */
bool unregister_function_for_event(void (*arg)(void));

이.register_function_for_event눈만 보다arg 않습니다 함수 이름이 보이지 않습니다.함수 포인터를 비교해야 동일한 함수를 두 번 등록하고 있음을 보고할 수 있습니다.

그리고 만약 당신이 지원하고 싶은 것이 있다면 다음과 같은 것.unregister_function_for_event위 내용을 보완하기 위해, 당신이 가지고 있는 유일한 정보는 기능 주소입니다.따라서 제거를 허용하기 위해 다시 한 번 전달하고 비교해야 합니다.

더 풍부한 정보에 관해서는 그렇습니다.함수 유형에 프로토타입이 포함된 경우 정적 유형 정보의 일부입니다.C에서는 프로토타입 없이 함수 포인터를 선언할 수 있지만 이는 진부한 기능입니다.

  1. 누가 왜 포인터를 비교하겠습니까?다음 시나리오를 생각해 보십시오.

    함수 포인터의 배열이 있습니다. 콜백 체인이라고 하면 각 포인터를 호출해야 합니다.목록은 다음으로 끝납니다.NULL(또는 보초) 함수 포인터.이 보초 포인터와 비교하여 목록의 끝에 도달했는지 비교해야 합니다.또한, 이 사례는 서로 다른 함수가 유사하더라도 다른 포인터를 가져야 한다는 이전 OP들의 우려를 정당화합니다.

  2. 컴파일러는 그것들을 다르게 보십니까?네. 유형 정보에는 인수와 반환 유형에 대한 모든 정보가 포함됩니다.

    예를 들어, 다음 코드는 컴파일러에 의해 거부됩니다.

    void foo(int a);
    void (*bar)(long) = foo; // Without an explicit cast
    
  1. 개념에 의해 함수의 고유성이 서로 다른 이름으로 보장되는 것을 감안할 때, 함수 포인터를 비교해야 하는 이유는 무엇입니까?

함수 포인터는 프로그램의 다른 시간에 다른 함수를 가리킬 수 있습니다.

다음과 같은 변수가 있는 경우

void (*fptr)(int);

그것은 어떤 기능이든 가리킬 수 있습니다.int투입 및 반환으로void.

예를 들면 다음과 같습니다.

void function1(int)
{
}

void function2(int)
{
}

다음을 사용할 수 있습니다.

fptr = function1;
foo(fptr);

또는:

fptr = function2;
foo(fptr);

당신은 다른 일을 하고 싶을지도 모릅니다.foo여부에 따라fptr한 함수 또는 다른 함수를 가리킵니다.따라서 다음의 필요성:

if ( fptr == function1 )
{
    // Do stuff 1
}
else
{
    // Do stuff 2
}
  1. 컴파일러는 함수 포인터를 특수 포인터로 보십니까?제 말은 그들이 공허함을 가리키는 포인터 *처럼 보일까요, 아니면 반환 유형, 인수 및 인수 유형과 같이 더 풍부한 정보를 보유하고 있을까요?

예, 함수 포인터는 객체를 가리키는 포인터와는 다른 특수 포인터입니다.

함수 포인터의 유형은 컴파일 시에 모든 정보를 가지고 있습니다.따라서 함수 포인터를 주면 컴파일러는 반환 유형, 인수 개수 및 유형과 같은 모든 정보를 갖게 됩니다.

함수 포인터에 대한 고전적인 부분은 다른 사람의 답변에서 이미 논의되어 있습니다.

  • 다른 포인터와 마찬가지로 함수에 대한 포인터는 다른 시간에 다른 개체를 가리킬 수 있으므로 비교하는 것이 의미가 있습니다.
  • 함수에 대한 포인터는 특수하므로 다른 포인터 유형에 저장해서는 안 됩니다(심지어는 안 됨).void *C 언어로도 가능).
  • 리치부분(함수서명)은 위 문장의 이유인 함수타입에 저장됩니다.

하지만 C는 (레거시) 함수 선언 모드를 가지고 있습니다.C는 모든 파라미터에 대해 Return type 및 type을 선언하는 Full prototype mode 외에, 소위 파라미터 list mode인 old K&R mode를 사용할 수 있습니다.이 모드에서는 선언이 반환 유형만 선언합니다.

int (*fptr)();

C에서 함수에 대한 포인터를 선언합니다.int임의의 매개변수를 허용합니다.단순히 잘못된 매개변수 목록과 함께 사용하는 것은 UB(undefined behavior)가 될 것입니다.

이것이 법적인 C 코드입니다.

#include <stdio.h>
#include <string.h>

int add2(int a, int b) {
    return a + b;
}
int add3(int a, int b, int c) {
    return a + b + c;
}

int(*fptr)();
int main() {
    fptr = add2;
    printf("%d\n", fptr(1, 2));
    fptr = add3;
    printf("%d\n", fptr(1, 2, 3));
    /* fprintf("%d\n", fptr(1, 2)); Would be UB */
    return 0;
}

내가 그렇게 하라고 충고한 척 하지 마!이제 이 기능은 낡은 기능으로 간주되므로 피해야 합니다.나는 단지 당신에게 그것에 대해 경고하는 것입니다.IMO는 일부 예외적으로 허용되는 사용 사례만 가질 수 있습니다.

다음과 유사한 기능을 어떻게 구현할지 상상해 보십시오.

있습니다.lpszClassName창 클래스를 서로 구별하기 위해 사용할 수 있는 문자열이 필요하지 않았거나 필요하지 않았다고 가정해 보겠습니다.

당신이 가지고 있는 것은 윈도우 클래스 절차입니다.lpfnWndProc(활자의).

그래서 만약 누군가가 같은 전화를 두 번 걸면 어떻게 하실 건가요?lpfnWndProc?
어떻게든 같은 클래스의 재등록을 감지하고 오류를 반환해야 합니다.

콜백 기능을 비교하는 것이 논리적으로 해야 할 일 중 하나입니다.

1) 여러 가지 상황이 있습니다.유한 상태 시스템의 일반적인 구현을 예로 들어보겠습니다.

typedef void state_func_t (void);

const state_func_t* STATE_MACHINE[] =
{
  state_init,
  state_something,
  state_something_else
};

...

for(;;)
{
  STATE_MACHINE[state]();
}

특정 상황에 대해 호출기에 추가 코드를 포함해야 할 수도 있습니다.

if(STATE_MACHINE[state] == state_something)
{
  print_debug_stuff();
}

2) 네, C 컴파일러는 그것들을 별개의 종류로 봅니다.사실 함수 포인터는 암묵적으로 변환되거나 변환될 수 없기 때문에 다른 C 유형보다 더 엄격한 유형 안전성을 갖습니다.void*은 할 수 (/1), (C116.3.2.3/1).또한 명시적으로 캐스팅할 수 없습니다.void*- 이렇게 하면 비표준 확장을 호출할 수 있습니다.

함수 포인터의 모든 것은 반환 값의 유형, 매개 변수의 유형 및 매개 변수의 수와 같이 그 유형을 결정하는 데 중요합니다.이 모든 것이 일치해야 합니다. 그렇지 않으면 두 함수 포인터가 호환되지 않습니다.

함수 포인터는 변수입니다.개념상 변수의 고유성은 서로 다른 이름으로 보장된다는 점에서 변수를 비교해야 하는 이유는 무엇입니까?때로는 두 변수가 같은 값을 가질 수도 있는데, 이러한 경우인지 여부를 확인하고자 합니다.

C는 인수 목록과 반환 값이 같은 함수에 대한 포인터를 같은 유형으로 간주합니다.

언급URL : https://stackoverflow.com/questions/48495625/function-pointers-in-c-nature-and-usage

반응형