Là void * function () một con trỏ tới hàm hay một hàm trả về void *?


26

Tôi bối rối về ý nghĩa của void *function().
Nó là một con trỏ để chức năng hoặc một chức năng trở lại void*? Tôi đã luôn sử dụng nó trên các cấu trúc dữ liệu như là một hàm đệ quy trả về một con trỏ, nhưng khi tôi thấy một mã trong đa luồng ( pthread) có một khai báo hàm tương tự. Bây giờ tôi bối rối không biết sự khác biệt giữa chúng là gì.


5
@goodvibr C đã được định dạng miễn phí (và C ++ "kế thừa" này). Thậm chí void*function();là đúng về mặt cú pháp. Ví dụ, đối với Python, họ đã chọn một quyết định khác - định dạng là một phần của cú pháp. IMHO, cả hai cách đều có pro và con.
Scheff

3
@goodvibr bạn càng cố gắng bảo vệ lập trình viên khỏi việc họ muốn, bạn càng nhận được nhiều thứ như java;)
idclev 463035818

2
@goodvibr Tùy chọn ít hơn, kém linh hoạt. Và, xin vui lòng, hãy nhớ rằng đó là hàng thập kỷ trước khi họ làm điều đó. Thật dễ dàng để phàn nàn sau đó ... ;-)
Scheff

2
Trong ngôn ngữ C, void *function()là một hàm lấy một số lượng đối số tùy ý và trả về một giá trị mà khi bị hủy đăng ký sẽ có kiểu void . Trong C ++, void* function()là một hàm không có đối số và trả về giá trị của con trỏ tới chỗ trống . Bạn nên quyết định về ngôn ngữ mà bạn đang hỏi về.
Stephen M. Webb

1
@ StephenM.Webb Bạn không thể bỏ qua avoid * . Rốt cuộc, ngay cả khi bạn có thể, bạn sẽ làm gì với một void?
Fabio nói Phục hồi lại

Câu trả lời:


38

Hàm có kiểu trả về void *.

void *function();

Vì vậy, tôi luôn thích trong các trường hợp như vậy để tách biểu tượng *khỏi tên hàm như

void * function();

Và như được Jarod42chỉ ra trong một bình luận, bạn có thể viết lại khai báo hàm trong C ++ bằng cách sử dụng kiểu trả về theo sau như

auto function() -> void *;

Nếu bạn muốn khai báo một con trỏ để hoạt động thì bạn nên viết

void ( *function )();

Hoặc là

void * ( *function )();

Hoặc một con trỏ tới hàm trả về con trỏ cho hàm

void * ( *( *function )() )();

2
Đó là lý do tại sao, tôi thích viết hơn void* function();. Điều đó không hấp dẫn ... ;-) (Bản chỉnh sửa đã xảy ra trong khi viết bài này.)
Scheff

trong mã tôi khai báo void * reader();sau đó pthread_create(&thread1,null,reader,reader_arg)thay vìpthread_create(&thread1,null,&reader,reader_arg)
user9515151

1
@Scheff: Hoặc thậm chí auto function() -> void*(C ++). :)
Jarod42

3
Hoặc một con trỏ để chức năng trả về con trỏ cho chức năng Đó là những gì typedefdành cho ... ;-)
Andrew Henle

1
@AndrewHenle Với typedef chúng tôi không có vấn đề gì. Một vấn đề phát sinh khi khai báo được sử dụng mà không có typedef hoặc khai báo bí danh. :)
Vlad từ Moscow

7

Bất cứ khi nào tôi không chắc chắn về các vấn đề cú pháp C, tôi muốn sử dụng tiện ích cdecl ( phiên bản trực tuyến ) để giải thích cho tôi. Nó dịch giữa cú pháp C và tiếng Anh.

Ví dụ, tôi nhập ví dụ của bạn void *foo()và nó trả về

khai báo foo là hàm trả con trỏ về void

Để xem cú pháp khác trông như thế nào, tôi nhập declare foo as pointer to function returning voidvà nó trả về

khoảng trống (* foo) ()

Điều này đặc biệt hữu ích khi bạn có nhiều cấp độ kiểu chữ, dấu sao hoặc dấu ngoặc trong một biểu thức.


2

Nó là một hàm trả về một con trỏ tới void.

Hãy nghĩ về tuyên bố của bạn theo cách này:

void *(function());

Đây sẽ là một hàm trả về void(hoặc không có gì):

void (*function2)();

Hãy nghĩ về tuyên bố trên theo cách này:

void ((*function2)());

Một cách dễ dàng hơn để viết những điều này là sử dụng typedefs:

typedef void *function_returning_void_pointer();
typedef void function_returning_nothing();

function_returning_void_pointer function;
function_returning_nothing *function2;

Điều này thường loại bỏ sự nhầm lẫn xung quanh các con trỏ hàm và dễ đọc hơn nhiều.


0

Các khai báo trong C / C ++ được đọc từ định danh bên ngoài theo quyền ưu tiên của toán tử .

Nhìn nhanh vào bảng ưu tiên toán tử C / C ++ trong wikipedia cho thấy toán tử gọi hàm ()có độ ưu tiên cao hơn toán tử gián tiếp *. Vì vậy, khai báo hàm của bạn đọc như thế này:

  • Bắt đầu tại định danh: function

  • function() một hàm không có đối số

  • void* function()và trả về a void*.

Nguyên tắc chung này cũng đúng với khai báo mảng ( []cũng có độ ưu tiên cao hơn *) và kết hợp cả hai. Vì thế

int *(*arr[42])();

được đọc là

  • arr
  • arr[42] một mảng gồm 42 phần tử
  • *arr[42] con trỏ đến
  • (*arr[42])() các hàm không có đối số và
  • int *(*arr[42])()trả lại một int*.

Phải mất một chút để làm quen với điều này, nhưng một khi bạn đã hiểu nguyên tắc, thật dễ dàng để đọc những tuyên bố đó một cách rõ ràng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.