Các dấu ngoặc đơn xung quanh một tên hàm có nghĩa là gì?


214

Trong một trong các tệp nguồn dự án của tôi, tôi đã tìm thấy định nghĩa hàm C này:

int (foo) (int *bar)
{
    return foo (bar);
}

Lưu ý: không có dấu hoa thị bên cạnh foo, vì vậy đây không phải là con trỏ hàm. Hoặc là nó? Điều gì đang xảy ra ở đây với cuộc gọi đệ quy?


7
Không, nó không phải là một con trỏ hàm - nó vẫn là một hàm thông thường có tên foo.
Nemanja Boric

Đây có phải là chức năng hoàn chỉnh?
asheeshr

2
Bạn có bằng chứng cho thấy chức năng này được sử dụng trong ngữ cảnh hữu ích không?
moooeeeep

1
... Trông giống như một số hàm giả có lẽ chỉ được viết để xem nếu nó biên dịch, trong nguồn hiện có, và đã bị xóa. Tôi sẽ loại bỏ nó (nếu đó là những gì chức năng thực sự làm), vì tốt nhất nó sẽ là vòng lặp vô hạn (tôi không chắc trình biên dịch C có được phép tối ưu hóa lệnh gọi đuôi đó để nhảy hay không), ở tình trạng tràn ngăn xếp tồi tệ nhất.
hyde

3
Dấu ngoặc trong khai báo C giúp làm mờ ngôn ngữ mơ hồ. Nhanh lên, là a(b);gì? Khai báo bnhư là một biến của loại a? Hoặc một cuộc gọi để hoạt động avới đối số b? Sự khác biệt là cú pháp và bạn không thể biết cách nào để phân tích cú pháp mà không cần tra cứu thông tin khai báo a; tức là các hàm postfix gọi các dấu ngoặc đơn hoặc các dấu ngoặc đơn tùy chọn xung quanh một bộ khai báo.
Kaz

Câu trả lời:


329

Trong trường hợp không có bất kỳ công cụ tiền xử lý nào đang diễn ra, foochữ ký của nó tương đương với

int foo (int *bar)

Bối cảnh duy nhất mà tôi thấy mọi người đặt dấu ngoặc đơn dường như không cần thiết xung quanh tên hàm là khi có cả hàm và macro giống như hàm có cùng tên và lập trình viên muốn ngăn chặn mở rộng macro.

Cách thực hành này ban đầu có vẻ hơi kỳ lạ, nhưng thư viện C tạo tiền lệ bằng cách cung cấp một số macro và hàm với tên giống hệt nhau .

Một cặp chức năng / macro như vậy là isdigit(). Thư viện có thể định nghĩa nó như sau:

/* the macro */
#define isdigit(c) ...

/* the function */
int (isdigit)(int c) /* avoid the macro through the use of parentheses */
{
  return isdigit(c); /* use the macro */
}

Hàm của bạn trông gần giống như trên, vì vậy tôi nghi ngờ đây cũng là những gì đang diễn ra trong mã của bạn.


2
Đó có thể là trường hợp ở đây là tốt; Tôi đã không tìm kiếm macro ... Và tôi không biết rằng việc mở rộng macro không diễn ra trong ngoặc đơn, Cảm ơn bạn đã chỉ ra điều đó!
dùng1859094

13
@ user1859094: Ở cái nhìn thứ hai, đây gần như chắc chắn là những gì đang diễn ra trong mã của bạn. Hàm foo(bar)bên trong đang sử dụng macro tương ứng.
NPE

78
@ user1859094 mở rộng macro diễn ra trong ngoặc đơn, nhưng việc mở rộng macro giống như hàm chỉ diễn ra nếu mã thông báo tiếp theo là dấu ngoặc trái (C99, 6.10.3 §10), do đó foo (int* bar)sẽ được thay thế, nhưng không (foo) (int *bar)(mã thông báo tiếp theo sau foo))
Virgile

4
Làm thế nào một chức năng như vậy sẽ được gọi là? Bạn sẽ gọi nó với dấu ngoặc đơn là tốt? Ví dụ, điều này sẽ làm việc : (isdigit)(5)?
gcochard

4
@Greg: Phải, đó chính xác là cách bạn gọi nó.
NPE

37

Các phép ẩn không thay đổi khai báo - nó vẫn chỉ xác định một hàm thông thường được gọi foo.

Lý do mà chúng đã được sử dụng gần như chắc chắn là vì có một macro giống như hàm được gọi là foođịnh nghĩa:

#define foo(x) ...

Sử dụng (foo)trong khai báo hàm ngăn chặn macro này được mở rộng ở đây. Vì vậy, những gì có khả năng xảy ra là một hàm foo()đang được xác định với phần thân của nó được mở rộng từ macro giống như hàm foo.


5
Khấu trừ tốt đẹp (mặc dù sử dụng dấu ngoặc đơn cho mục đích này nên bị pháp luật trừng phạt).
ugoren

3
@ugoren: sử dụng parens xung quanh tên hàm là cách duy nhất để ngăn chặn việc mở rộng macro cho macro giống như hàm. Đôi khi nó là một công cụ cần thiết.
Michael Burr

7
@MichaelBurr, cũng có tùy chọn không có macro và chức năng có cùng tên. Tôi biết bạn không thể luôn kiểm soát mọi thứ, nhưng nếu bạn đạt được giải pháp này, tôi sẽ nói có gì đó không ổn.
ugoren

-3

Các dấu ngoặc là vô nghĩa.
Mã bạn hiển thị không có gì ngoài một đệ quy vô hạn.

Khi xác định một con trỏ hàm, đôi khi bạn thấy các dấu ngoặc đơn có nghĩa là gì đó. Nhưng đây không phải là trường hợp ở đây.


6
Rõ ràng là không; các dấu ngoặc ngăn chặn mở rộng vĩ mô. Xem câu trả lời được chấp nhận.
Kevin

12
@Kevin, Câu trả lời của tôi là về mã được hiển thị và là chính xác cho nó. Trong hầu hết mọi câu hỏi C ở đây, giả sử các định nghĩa tiền xử lý chưa biết có thể thay đổi mọi thứ. Trong trường hợp này, các câu trả lời xem xét bộ tiền xử lý thực sự tốt hơn, nhưng nó không làm cho tôi sai.
ugoren
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.