2015-06-01 27 views
7
void funcPtr(int a); 

int main(){ 
    int k=1; 
    void (*funcPtr2)(int); 

    funcPtr2 = (void*)(funcPtr); 
    // funcPtr2 = (void(*)(int))(funcPtr); 

    (*funcPtr2)(k); 
    return 0; 
} 

void funcPtr(int a){ 
    printf("%d", a); 
} 

Sự khác nhau giữa (void*)(void(*)(argument type) trong kiểu nhập con trỏ hàm là gì?Sự khác nhau giữa (void *) và (void (*) (loại đối số)) là gì?

Kết quả là nó không xảy ra cảnh báo.

Điều này có sai không? về (void*) loại đúc

+0

'lỗi: chuyển đổi không hợp lệ từ 'void *' thành 'void (*) (int)' ' – user657267

+0

Tại sao một diễn viên ở nơi đầu tiên. Con trỏ hàm và hàm địa chỉ * khớp *? Và bạn đã chính xác một phần; không có cảnh báo, [lỗi phẳng của nó] (http://ideone.com/8BpCPx) – WhozCraig

+6

C hoặc C++? Chọn một_. –

Trả lời

7

Is this wrong? about (void*) type casting

Vâng, đúng vậy.

Chuẩn C không cho phép chuyển đổi con trỏ hàm thành con trỏ đối tượng hoặc gán giữa chúng. Nếu bạn tăng mức độ cảnh báo của trình biên dịch, bạn có thể nhận được cảnh báo/lỗi như biên dịch với:

gcc -Wall -Wextra -pedantic-errors -std=c11 file.c 

Tôi không chắc chắn tại sao bạn nghĩ về việc đúc con trỏ hàm. Cung cấp các loại con trỏ hàm phù hợp với chức năng, chỉ cần gán nó:

funcPtr2 = funcPtr; 

Ngoài:

Bạn có thể sử dụng con trỏ hàm giống như một chức năng:

funcPtr2(k); 

và sử dụng một mẫu chuẩn cho main chẳng hạn như:

int main(void) 
+0

Hạn chế không cho phép mã <-> ngày chuyển đổi con trỏ dữ liệu trở về ngày của Mô hình bộ nhớ Intel (http://en.wikipedia.org/wiki/Intel_Memory_Model) và có thể tương tự như contraptions trên các kiến ​​trúc khác. Ví dụ. trong mô hình "trung bình", 'sizeof (void *) == 2', nhưng' sizeof (void (*) (void)) == 4', làm cho các chuyển đổi không an toàn. Tất nhiên, không có nền tảng nào trong số các nền tảng và mô hình bộ nhớ này có bất kỳ sự liên quan nào liên quan đến POSIX. –

0
(void*) 

chuyển con trỏ đến con trỏ để void hoặc con trỏ chung.

void(*)(int) 

là con trỏ hàm cho hàm tham gia đối số int và không trả về gì.

int fn(float f) { return f * 3.14; } 

void* ptr = fn; 

Sẽ làm ptr các địa chỉ của lệnh máy đầu tiên của fn nhưng không cho phép bạn sử dụng nó.

int(*ptr)(float) = fn; 
// or 
typedef int(FnPtr)(float); 
FnPtr* ptr = fn; 

mất địa chỉ trong một cách mà trình biên dịch biết những loại gọi hàm đã được chỉ ra để bạn có thể gọi hàm

int n = ptr(2.5); 

nào có thể hữu ích để làm một cái gì đó giống như

void get_data(int socket, int timeout, void(*callback)(char*, size_t)); 

Chức năng nào tôi có thể chuyển chức năng khác.

void recv_data(char* data, size_t len) 
{ 
    ... 
} 

... 

get_data(socket, 60, recv_data); 
+1

Trong C, bạn không thể truyền một con trỏ hàm tới 'void *'. –

+0

@undur_gongor Một số trình biên dịch cho phép nó ở các mức cảnh báo nhất định, và tôi đang làm điều này trên kindle của tôi, vì vậy tôi đã chọn không để tranh luận rằng trường hợp. – kfsone

+0

(Nhưng đó là lý do tại sao tôi chọn 'sẽ') – kfsone

1

Đây là vấn đề với dlsym, đã tuyên bố void *dlsym(void *restrict handle, const char *restrict name). dlsym trả về một con trỏ tới hàm có tên name được xác định trong và có thể truy cập thông qua handle.
Tuy nhiên, như trạng thái @BlueMoon, điều này không được xác định trong ISO C và gcc thực sự phàn nàn nếu được thực hiện. POSIX đã cố gắng giải quyết vấn đề đó và yêu cầu thực hiện tuân thủ để làm cho dàn diễn viên đó được xác định rõ ràng trong tính không xác định của nó.

Từ POSIX

Note that conversion from a void * pointer to a function pointer as in:

fptr = (int (*)(int))dlsym(handle, "my_function");

is not defined by the ISO C standard. This standard requires this conversion to work correctly on conforming implementations.

Một cách khác để làm cho điều đó diễn viên Tuân thủ là lần đầu tiên chuyển đổi con trỏ hàm để void** và sau đó dereference nó. Điều này nên được xác định rõ. Trong trường hợp của bạn,

void funcPtr(int a); /* symbol to extract */ 

int main(void) 
{ 
    void (*fn)(int); 
    *(void**)(&fn) = dlsym(your_handle, "funcPtr"); 


    fn(5); 
} 
Các vấn đề liên quan