2014-08-28 7 views
2
typedef void (*LoopCallback)(int fd, void * arg); 

LoopCallback func_ptr = 0; 

void call_back(int value) 
{ 
    printf("%d", value); 
} 

void sys_register_input(LoopCallback call_back) 
{ 
    func_ptr = call_back; 
} 

int main() 
{ 
    sys_register_input((LoopCallback)call_back); 
    func_ptr(33, 0); 
} 

이 코드는 레거시 프로젝트 중 하나에서 발견됩니다.이 캐스팅은 c에서 유효합니까?함수 포인터로 함수 캐스팅

편집 : 전화 기능 PTR

+0

아니요, 그렇지 않습니다. 매개 변수의 수를 끄면 적어도 Win32 코드 (stdcall)에는 큰 혼란이있을 것입니다. – kay

+0

표준 C에서는 유효하지 않지만 일부 구현에서는 작동 할 수 있습니다. –

답변

5

아니, 그것은 유효하지 않습니다. 호출자가 예상 한 프로토 타입이 호출되는 함수의 프로토 타입과 일치하지 않으므로 정의되지 않은 동작이 발생할 수 있습니다. 구체적인 결과는 컴파일러 및 호출 규칙 (호출 된 함수는 단지 arg에 쓰레기가 표시되거나 스레드 스택이 손상되어 충돌이 발생할 수 있음)와 같은 요인에 따라 다릅니다.

+0

sys_register_input이 call_back을 호출하지 않더라도? – user3689849

+0

이 작업을 수행하는 올바른 방법은 무엇입니까? – user3689849

+1

상황에 따라 다릅니다. 함수 포인터를 해당 서명이 필요한 함수에 전달하거나 함수를 호출하는 호환 가능한 서명이있는 래퍼를 만듭니다 (사용 가능한 인수를 전달하고 다른 인수에 값 제공). –

3

앤드류 메디코 (Andrew Medico)는 그것이 유효하지 않다고 말하면서 옳았습니다. 그러나 실제로는 현재의 ABIs의 대다수에서 작동하고 확실하게 작동 할 것입니다.

오늘날 사용되는 대부분의 ABI는 호출자가 모든 스택 유지 보수 및/또는 레지스터에서 인수를 전달할 수있게하므로 함수가 인수하는 것보다 더 많은 인수를 주면 아무도 통지하지 않습니다. 사용되지 않는 스택 공간이 있거나 사용되지 않는 레지스터에 값을 쓰면됩니다.

실제 사실은 종종 그 반대로도 할 수 있습니다. 즉, 함수가 요구하는 것보다 적은 인수를주는 것입니다. 이러한 인수에 대해 정의되지 않은 값을 받겠지 만 사용하지 않으면 문제가되지 않습니다. 사실 표준 POSIX C 함수 open()은이 동작에 따라 달라지며, 이는 C ABI가 지금과 역사적으로 이러한 문제에 대해 얼마나 흔하지 않을지를 보여줍니다.

가능하다면 이런 종류의 동작에 의존하지 말아야합니다. 특히 과도하게 휴대 할 필요가 없다면 은 실제로 이유를 참조하십시오. 당신 , 그러나, 당신이하고있는 일을 잘 알고 있어야하고 왜 그런지 모르거나 왜 그런지 모르겠다면 이런 종류의 트릭을 사용해서는 안됩니다. 작업.

호출자가 스택을 설정했지만 호출 수신자가이를 정리하는 Pascal/BASIC 형 ABI (Windows의 경우 stdcall)에 함수를 작성하는 경우가 있습니다. 이 경우 호출자는 두 개의 인수를 가졌지 만 호출 수신자는 하나만 튀어 나오므로 스택 포인터는 반환 후 호출 전 값과 일치하지 않으므로 호출자 함수를 비롯한 모든 종류의 이상한 요소가 발생합니다 다시 리턴 할 때 적절한 리턴 주소를 사용하지 마십시오. 충돌이 보장됩니다. 그러나 이것은 C에서 아주 이상한 일입니다.

관련 문제