C/C++에 기능이 있는지 확인하는 방법은?
내 코드의 특정 상황에서는 해당 함수가 정의된 경우에만 함수를 호출하거나 그렇지 않으면 호출하지 않습니다.어떻게 하면 이것을 이룰 수 있을까요?
like:
if (function 'sum' exists ) then invoke sum ()
아마도 이 질문을 하는 다른 방법은 함수가 런타임에 정의되었는지 여부를 결정하고, 정의된 경우 호출하는 방법일 것입니다.
GCC를 사용하면 다음을 수행할 수 있습니다.
void func(int argc, char *argv[]) __attribute__((weak)); // weak declaration must always be present
// optional definition:
/*void func(int argc, char *argv[]) {
printf("FOUND THE FUNCTION\n");
for(int aa = 0; aa < argc; aa++){
printf("arg %d = %s \n", aa, argv[aa]);
}
}*/
int main(int argc, char *argv[]) {
if (func){
func(argc, argv);
} else {
printf("did not find the function\n");
}
}
함수에 대한 코멘트를 해제하면 함수가 실행됩니다. 그렇지 않으면 "함수를 찾지 못했습니다\n"라고 인쇄됩니다.
sum을 선언하면 다음과 같이 선언할 수 있습니다.
#define SUM_EXISTS
int sum(std::vector<int>& addMeUp) {
...
}
그러면 사용하러 오면 다음을 수행할 수 있습니다.
#ifdef SUM_EXISTS
int result = sum(x);
...
#endif
실행 시에 모든 작업이 완료되는 스크립트 언어에서 오신 것 같습니다.C++와 함께 기억해야 할 주요 사항은 두 단계입니다.
- 컴파일시간
- 전처리기 실행
- 템플릿 코드가 실제 소스 코드로 바뀝니다.
- 소스코드는 기계코드로 전환됩니다.
- 런타임
- 기계 코드가 실행됩니다.
.#define
그런 일들은 컴파일 타임에 일어납니다.
....
정말로 런타임에 모든 작업을 수행하고 싶으셨다면..일부 구성요소 아키텍처 제품을 사용하는 데 관심이 있을 수도 있습니다.
아니면 플러그인 종류의 아키텍처가 여러분이 원하는 것일지도 모릅니다.
이 되는 입니다 (입니다 (dlsym
, 함수 포인터, ...), 존재하지 않는 함수를 참조하여 C++ 코드를 컴파일할 수 없습니다.최소한 함수를 선언해야 합니다. 선언하지 않으면 코드가 컴파일되지 않습니다.아무것도(컴플레이션 단위, 일부 오브젝트 파일, 일부 라이브러리) 함수를 정의하지 않으면 링커가 불만을 제기합니다(약하지 않은 한 아래 참조).
하지만 당신은 왜 그런 질문을 하는지 정말로 설명해야 합니다.나는 추측할 수 없고, 당신의 명시되지 않은 목표를 달성할 수 있는 방법이 있습니다.
이름 망글링이 없는 기능이 필요한 경우가 많으며, 예를 들어 다음과 같이 선언됩니다.extern "C"
.
GCC 를, 를를 도 있습니다.weak
선언의 함수 특성입니다.그런 다음 링커는 정의되지 않은 약한 기호를 null로 설정합니다.
별첨
어떤 입력에서 함수 이름을 가져온다면, 함수의 일부만 그런 식으로 호출할 수 있어야 한다는 것을 알아야 합니다(무관심하게 임의 함수를 호출하면 충돌이 발생합니다!). 그리고 그 부분을 명시적으로 구성하는 것이 좋습니다.그러면 당신은 a를 사용할 수 있습니다.std::map
, 아니면dlsym
집합의 각된 상태에서됨)extern "C"
합니다. 주목할 점은(는)dlopen
NULL
이 연동해야 . 당신은 그것을 링크해야 합니다.-rdynamic
정확하게 작동시키는 것입니다.
적합하게 정의된 함수의 부분 집합만 해당 함수의 이름으로 호출하려고 합니다.를 들어,어,다 겁니다.abort
,exit
, 아니면fork
.
NB. 호출된 함수의 서명을 동적으로 알고 있다면 libffi를 사용하여 호출할 수 있습니다.
저는 포스터가 실제로 SFINAE 체크/디스패치의 라인을 따라 더 많은 것을 찾고 있었다고 의심합니다.C++ 템플릿을 사용하면 원하는 함수를 호출하는 함수와 아무 것도 호출하지 않는 함수를 템플릿 함수로 정의할 수 있습니다(함수가 존재하지 않는 경우).그런 다음 원하는 기능에 따라 첫 번째 템플릿을 지정하여 해당 기능이 없을 때 템플릿이 잘못된 형식이 되도록 할 수 있습니다.이것은 C++ 템플릿 대체 실패가 오류(SFINAE)가 아니기 때문에 컴파일러가 두 번째 경우(예를 들어 아무것도 할 수 없음)로 되돌아가기 때문에 유효합니다.
우수한 예는 여기를 참조하십시오.함수의 존재 여부를 확인하기 위해 템플릿을 작성할 수 있습니까?
함수에 포인터를 사용합니다.
//initialize
typedef void (*PF)();
std::map<std::string, PF> defined_functions;
defined_functions["foo"]=&foo;
defined_functions["bar"]=&bar;
//if defined, invoke it
if(defined_functions.find("foo") != defined_functions.end())
{
defined_functions["foo"]();
}
호출할 함수가 어떤 라이브러리에 있는지 알고 있으면 사용하여 함수에 대한 포인터가 무엇인지 확인할 수 있습니다.
편집: 저는 아마도 이 접근법을 사용하지 않을 것입니다. 대신 Matiu의 해결책을 추천합니다. 훨씬 더 좋은 방법이라고 생각하기 때문입니다.만,dlsym()
잘 알려져 있지 않아서 제가 한번 지적해 볼까 했습니다.
합니다.#pragma weak
지원하는 컴파일러의 경우(약한 기호 위키백과 항목 참조).
이 예제 및 코멘트는 공유 라이브러리 및 동적 로딩에 대한 Inside Story에서 가져온 것입니다.
#pragma weak debug
extern void debug(void);
void (*debugfunc)(void) = debug;
int main() {
printf(“Hello World\n”);
if (debugfunc) (*debugfunc)();
}
취약한 프래그마를 사용하여 링커가 해결되지 않은 기호 [...]를 무시하도록 강제할 수 있습니다. 프로그램은 디버그 ()가 실제로 객체 파일에 정의되어 있는지 여부에 관계없이 컴파일하고 링크합니다.기호가 정의되지 않은 상태로 남아 있으면 링커는 일반적으로 값을 0으로 바꿉니다.따라서 이 기법은 프로그램이 전체 응용 프로그램을 다시 컴파일할 필요가 없는 선택 코드를 호출하는 데 유용한 방법이 될 수 있습니다.
따라서 c++11을 사용하는 경우에는 다음과 같은 기능을 사용할 수 있습니다.
파일 시작 부분에 이 내용을 입력해야 합니다.
#include <functional>
함수의 종류는 다음과 같은 형식으로 선언됩니다.
std::function< return_type (param1_type, param2_type) >
다음과 같이 합에 대한 함수를 고정하는 변수를 추가할 수 있습니다.
std::function<int(const std::vector<int>&)> sum;
쉽게 처리하려면 매개변수 유형을 짧게 설정합니다.
using Numbers = const std::vectorn<int>&;
그런 다음 functor var를 다음 중 하나로 입력할 수 있습니다.
람다:
sum = [](Numbers x) { return std::accumulate(x.cbegin(), x.cend(), 0); } // std::accumulate comes from #include <numeric>
함수 포인터:
int myFunc(Numbers nums) {
int result = 0;
for (int i : nums)
result += i;
return result;
}
sum = &myFunc;
'bind'가 만들어낸 것:
struct Adder {
int startNumber = 6;
int doAdding(Numbers nums) {
int result = 0;
for (int i : nums)
result += i;
return result;
}
};
...
Adder myAdder{2}; // Make an adder that starts at two
sum = std::bind(&Adder::doAdding, myAdder);
마지막으로 사용 방법은 간단합니다.
if (sum)
return sum(x);
요약하면, 함수는 함수에 대한 새로운 포인터이지만, 더 다양합니다.컴파일러가 충분히 확신한다면 실제로는 인라인이 될 수 있지만 일반적으로 함수 포인터와 동일합니다.
std::bind 및 lambd's와 결합하면 오래된 스타일의 C 함수 포인터보다 훨씬 우수합니다.
그러나 이들은 c++11 이상의 환경에서 작동한다는 것을 기억해야 합니다.(C 또는 C++03에는 없음).
C++에서 구성원이 존재하는지 확인하는 트릭의 수정된 버전은 런타임 대신 컴파일 시간에 사용자가 원하는 것을 제공해야 합니다.
#include <iostream>
#include <type_traits>
namespace
{
template <class T, template <class...> class Test>
struct exists
{
template<class U>
static std::true_type check(Test<U>*);
template<class U>
static std::false_type check(...);
static constexpr bool value = decltype(check<T>(0))::value;
};
template<class U, class = decltype(sum(std::declval<U>(), std::declval<U>()))>
struct sum_test{};
template <class T>
void validate_sum()
{
if constexpr (exists<T, sum_test>::value)
{
std::cout << "sum exists for type " << typeid(T).name() << '\n';
}
else
{
std::cout << "sum does not exist for type " << typeid(T).name() << '\n';
}
}
class A {};
class B {};
void sum(const A& l, const A& r); // we only need to declare the function, not define it
}
int main(int, const char**)
{
validate_sum<A>();
validate_sum<B>();
}
clang을 사용한 출력은 다음과 같습니다.
sum exists for type N12_GLOBAL__N_11AE
sum does not exist for type N12_GLOBAL__N_11BE
A가 아닌 int를 사용했을 때 이상한 일들이 일어났음을 지적해야겠습니다 (sum()
전에 신고해야 합니다.sum_test
를 위해exists
일하려고, 어쩌면exists
이름이 맞지 않습니다.내가 A를 사용했을 때 문제가 발생하지 않았던 일종의 템플릿 확장.ADL과 관련된 일이겠지
이 답변은 테스트 방법에 대한 다른 답변을 보완하기 위해 글로벌 기능에 대한 것입니다.이 답변은 전역 함수에만 적용됩니다.
먼저 별도의 네임스페이스에 폴백 더미 함수를 제공합니다.그런 다음 템플릿 매개 변수 안에서 함수 호출의 반환 유형을 결정합니다.리턴 타입에 따라 폴백 함수인지 원하는 함수인지 결정합니다.
함수의 네임스페이스에 다음과 같은 내용을 추가하는 것이 금지된 경우std::
, 그런 다음 ADL을 사용하여 테스트에서 적합한 기능을 찾아야 합니다.
예를들면,std::reduce()
는 c++17의 일부이지만 c++17을 지원해야 하는 초기 gcc 컴파일러는 정의하지 않습니다.std::reduce()
여부를 할 수 있는 과 같습니다.std::reduce
을 선언합니다.컴파일 탐색기에서 두 경우 모두 올바르게 작동합니다.
#include <numeric>
namespace fallback
{
// fallback
std::false_type reduce(...) { return {}; }
// Depending on
// std::recuce(Iter from, Iter to) -> decltype(*from)
// we know that a call to std::reduce(T*, T*) returns T
template <typename T, typename Ret = decltype(reduce(std::declval<T*>(), std::declval<T*>()))>
using return_of_reduce = Ret;
// Note that due to ADL, std::reduce is called although we don't explicitly call std::reduce().
// This is critical, since we are not allowed to define any of the above inside std::
}
using has_reduce = fallback::return_of_reduce<std::true_type>;
// using has_sum = std::conditional_t<std::is_same_v<fallback::return_of_sum<std::true_type>,
// std::false_type>,
// std::false_type,
// std::true_type>;
#include <iterator>
int main()
{
if constexpr (has_reduce::value)
{
// must have those, so that the compile will find the fallback
// function if the correct one is undefined (even if it never
// generates this code).
using namespace std;
using namespace fallback;
int values[] = {1,2,3};
return reduce(std::begin(values), std::end(values));
}
return -1;
}
위의 수 없을 와할 수 .std::is_same
그리고.std::contitional
.
를 들어, , 합니다 여부를 int sum(int, int)
는 현재 컴파일 단위로 선언됩니다.요를 .test_sum_ns::return_of_sum
.int
그리고.std::false_type
그렇지 않으면(또는 좋아하는 다른 특별한 유형).
using has_sum = std::conditional_t<std::is_same_v<test_sum_ns::return_of_sum,
std::false_type>,
std::false_type,
std::true_type>;
그러면 다음 유형을 사용할 수 있습니다.
if constexpr (has_sum::value)
{
int result;
{
using namespace fallback; // limit this only to the call, if possible.
result = sum(1,2);
}
std::cout << "sum(1,2) = " << result << '\n';
}
: 가 .using namespace
그렇지 는 입니다 를 찾지 .if constexpr
불평할 겁니다일반적으로 당신은 피해야만 합니다.using namespace
네임스페이스 내부의 기호가 나중에 변경되면 코드가 끊어질 수 있기 때문입니다.이 의 예제로,같이 로 제한합니다.
언급URL : https://stackoverflow.com/questions/8814705/how-to-check-if-a-function-exists-in-c-c
'programing' 카테고리의 다른 글
이름이 있는 DispatcherServlet에서 URI가 있는 HTTP 요청에 대한 매핑을 찾을 수 없습니다. (0) | 2023.10.07 |
---|---|
mySQL 피벗/두 개의 열 ID를 기준으로 행 병합/열로 병합/이동 (0) | 2023.10.07 |
혼합된 컨텐츠가 있는 보안 연결을 통해 지리적 위치에 대한 액세스가 차단되었습니다. (0) | 2023.10.07 |
Git 하위 모듈 푸시 (0) | 2023.10.07 |
jQuery: 클릭 시 설정된 증분(픽셀 단위)을 스크롤 다운 페이지로 이동하시겠습니까? (0) | 2023.10.07 |