programing

함수 포인터로 함수 전달

instargram 2023. 6. 26. 21:01
반응형

함수 포인터로 함수 전달

저는 C++ 앱에서 C 라이브러리를 사용하려고 시도하고 있으며 다음과 같은 상황에 처해 있습니다(저는 제 C를 알고 있지만 C++은 꽤 생소합니다).C 쪽에는 함수 포인터를 인수로 사용하는 함수 모음이 있습니다.C++ 쪽에는 C 함수에 필요한 함수 포인터와 동일한 서명을 가진 함수가 있는 객체가 있습니다.C++ 함수를 함수 포인터로 사용하여 C 함수로 전달할 수 있는 방법이 있습니까?

C 코드(또는 C++ 코드)에 대한 함수 포인터로 C++ 함수 개체에 포인터를 직접 전달할 수 없습니다.

또한 C 코드에 대한 콜백을 이식 가능하게 전달하려면 적어도 다음과 같이 선언되어야 합니다.extern "C"가 필요합니다.적어도 일부 API에는 특정 함수 호출 규칙과 추가 선언 수정자가 필요하기 때문입니다.

대부분의 환경에서 C와 C++는 호출 규칙이 같고 이름만 다를 뿐이므로 모든 전역 함수나 정적 멤버가 작동합니다.를 하만당신여통마합니다야해리무화로 끝내야 합니다.operator()정상 기능으로

  • 함수에 상태가 없는 경우(일부 형식 요구 사항 등을 충족하기 위한 목적일 뿐):

    class MyFunctor {
      // no state
     public:
      MyFunctor();
      int operator()(SomeType &param) const;
    }
    

    함수를 생성하고 연산자()를 실행하는 일반 외부 "C" 함수를 작성할 수 있습니다.

    extern "C" int MyFunctorInC(SomeType *param)
    {
      static MyFunctor my_functor;
      return my_functor(*param);
    }
    
  • 함수에 상태가 있는 경우(예:

    class MyFunctor {
      // Some fields here;
     public:
      MyFunctor(/* some parameters to set state */);
      int operator()(SomeType &param) const;
      // + some methods to retrieve result.
    }
    

    그리고 C 콜백 함수는 일종의 사용자 상태 매개 변수(일반적으로 void*)를 사용합니다.

    void MyAlgorithmInC(SomeType *arr,
                        int (*fun)(SomeType *, void *),
                        void *user_state);
    

    일반 외부 "C" 함수를 작성하여 상태 매개 변수를 함수 객체에 캐스팅할 수 있습니다.

    extern "C" int MyFunctorInC(SomeType *param, void *user_state)
    {
      MyFunctor *my_functor = (MyFunctor *)user_state;
      return (*my_functor)(*param);
    }
    

    다음과 같이 사용합니다.

    MyFunctor my_functor(/* setup parameters */);
    MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);
    
  • 그렇지 않으면 ("런타임에 기계 코드를 생성하지 않고" 등과 같이 정상적으로) 일부 정적(글로벌) 또는 스레드 로컬 스토리지를 사용하여 함수를 외부 "C" 함수로 전달하는 것이 유일합니다.이렇게 하면 코드로 수행할 수 있는 작업이 제한되고 보기 흉하지만 작동합니다.

저는 구글을 사용하여 이 ""을 찾았습니다.가능할 것 같지만 추천하지는 않을 것 같습니다.예제 소스 코드에 대한 직접 링크입니다.

아니, 물론입니다.C 함수의 서명은 인수를 함수로 사용합니다.

void f(void (*func)())
{
  func(); // Only void f1(), void F2(), ....
}

함수가 있는 모든 트릭은 템플릿 함수에서 사용됩니다.

template<class Func>
void f (Func func)
{
    func(); // Any functor
}

된 C 는 C++로 .extern "C"함수 - 함수를 직접 사용할 수 없습니다.당신은 그 콜백으로 사용할 일종의 래퍼 함수를 작성하고 해당 래퍼가 함수를 호출하도록 해야 합니다.물론 콜백 프로토콜은 함수에 컨텍스트를 전달하는 방법이 있어야 함수에 도달할 수 있습니다. 그렇지 않으면 작업이 상당히 까다로워집니다.대부분의 콜백 계획은 문맥을 전달하는 방법을 가지고 있지만, 저는 그렇지 않은 뇌사자들과 함께 작업했습니다.

자세한 내용은 이 답변을 참조하십시오(그리고 콜백이 반드시 필요하다는 일화적인 증거는 댓글을 참조하십시오).extern "C"정적 멤버 함수뿐만 아니라):

당신은 할 수 없을 것 같습니다.operator()함수 객체는 실제로 멤버 함수이고, C는 그것들에 대해 아무것도 모릅니다.

당신이 사용할 수 있어야 하는 것은 무료 C++ 함수 또는 클래스의 정적 함수입니다.

포인터로 할 수 의 첫 번째 는 GCC 사 멤 플 버 포 수 플 를 인 다 함 레 니 같 있 다 습 다 니 과 음 습 인 번 는 첫 수 째 함 레 인 호 의 수 의 수 에 는 되 출 수 터 해 인 용 포 인 함 할 수 환 터 인 터 로 포 this).

설명서의 해당 링크를 확인하십시오.

이를 위해서는 다음이 필요합니다.-Wno-pmf-conversions플래그를 눌러 비표준 기능에 대한 각 경고를 잠재웁니다.C 스타일 라이브러리를 C++ 스타일 프로그래밍과 연결하는 데 매우 편리합니다.멤버 함수 포인터가 상수일 때는 코드를 생성할 필요조차 없습니다. API는 어쨌든 이 인수 순서를 사용합니다.

만약 당신이 이미 함수를 가지고 있다면, 그러한 방식으로 함수를 평평하게 하는 것은 아마도 그것의 평평하게 하는 것을 의미할 것입니다.operator()함수 클래스 포인터 자체를 첫 번째 인수로 사용하여 호출해야 하는 함수를 제공합니다.그것은 반드시 그렇게 많은 도움이 되지는 않지만 적어도 C 연결이 있습니다.

그러나 적어도 당신이 함수를 거치지 않을 때 이것은 도움이 되고 무의미한 C 연결 대체를 제공합니다.std::mem_fn<functional>.

이것이 정적 메서드인지 인스턴스 메서드인지에 따라 다르며, 정적 메서드인 경우 className::functionName 함수로 함수를 전달할 수 있습니다. 인스턴스 메서드인 경우 C# 등의 대리자와 동일한 방식으로 연결할 수 없기 때문에 상당히 복잡합니다.

이것을 하는 가장 좋은 방법은 객체의 인스턴스와 함수 포인터로 인스턴스화되는 홀딩 클래스를 만드는 것입니다. 홀딩 클래스는 함수를 직접 호출할 수 있습니다.

C++ 함수에 오버로드된 연산자가 있기 때문에 아니라고 생각합니다.()멤버 함수이므로 멤버 함수 포인터가 필요합니다.클래스의 인스턴스 없이는 호출할 수 없기 때문에 일반 C 함수 포인터와는 완전히 다른 데이터 유형입니다.당신은 정상 기능이나 정적 멤버 기능을 C 라이브러리에 전달해야 합니다.과부하가 걸렸기 때문에()연산자는 정적일 수 없습니다. 당신은 할 수 없습니다.C 라이브러리에 정상적인 비회원 함수 또는 정적 멤버 함수를 전달해야 하며, 여기서 C++ 함수를 호출할 수 있습니다.

흠, 아마도 당신은 당신의 함수 객체를 감싸는 무료 템플릿 함수를 쓸 수 있을 것입니다.모두 동일한 서명을 가진 경우 이 작업이 가능합니다.이와 같이(테스트되지 않음):

template<class T>
int function_wrapper(int a, int b) {
    T function_object_instance;

    return funcion_object_instance( a, b );
}

이렇게 하면 두 개의 int를 사용하고 int를 반환하는 모든 함수에 사용할 수 있습니다.

함수 포인터 콜백을 사용하는 많은 C API에는 사용자 상태에 대한 void* 매개 변수가 있습니다.만약 당신이 그것들 중 하나를 가지고 있다면, 당신은 운이 좋은 것입니다 - 당신은 사용자 데이터를 일종의 참조나 키로 취급하여 함수를 찾은 다음 실행할 수 있습니다.

그렇지 않으면, 안 됩니다.

C11을 할 수 .std::bind

#include <stdio.h>
#include <functional>

class aClass
{
public:
  int i = 5;
  aClass(int i_) : i(i_) {}
  void operator()(int a, int b) {
      i = i + 1;
      printf ("%d + %d = %d  i = %d\n", a, b, a + b + i, i);
  }
};

void test (int a, int b)
{
  printf ("%d - %d = %d\n", a, b, a - b);
}

template <class op>
void function1 (op function)
{
  function (1, 1);
}

int
main (int argc, const char *argv[])
{
  aClass a(1);
  //  function1 (a);  // this is the wrong way of using it

  using namespace std::placeholders;
  std::function<void(int,int)>  callback;
  callback = std::bind(&aClass::operator(), &a, _1, _2);
  
  function1 (callback);
  function1 (callback);

  function1 (test);
  function1 (test);

  return 0;
}

언급URL : https://stackoverflow.com/questions/1840029/passing-functor-as-function-pointer

반응형