khai báo hàm không phải là nguyên mẫu


158

Tôi có một thư viện tôi đã tạo,

mylib.c:

#include <mylib.h>
int
testlib() {
    printf("Hello world\n");
    return (0);
}

mylib.h:

#include <stdio.h>
extern int testlib();

Trong chương trình của tôi, tôi đã cố gắng gọi chức năng thư viện này:

myprogram.c:

#include <mylib.h>

int
main (int argc, char *argv[]) {
    testlib();
    return (0);
}

Khi tôi cố gắng biên dịch chương trình này, tôi gặp lỗi sau:

Trong tệp bao gồm từ myprogram.c: 1
mylib.h: 2 cảnh báo: khai báo hàm không phải là nguyên mẫu

Tôi đang sử dụng: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

Câu hỏi của tôi là, cách thích hợp để khai báo một nguyên mẫu hàm là gì?


1
Xóa extern khỏi khai báo trong mylib.h Đặc biệt nếu bạn đang viết chương trình C thuần túy, khai báo extern là không cần thiết ở đó.
Ryan Ahearn

Câu trả lời:


333

Trong C int foo()int foo(void)là các chức năng khác nhau. int foo()chấp nhận số lượng đối số tùy ý, trong khi int foo(void)chấp nhận 0 đối số. Trong C ++, chúng có nghĩa tương tự. Tôi đề nghị bạn sử dụng voidnhất quán khi bạn có nghĩa là không có đối số.

Nếu bạn có một biến a, extern int a;là một cách để nói với trình biên dịch alà ký hiệu có thể có trong một đơn vị dịch khác (trình biên dịch C nói cho tệp nguồn), đừng giải quyết nó cho đến khi thời gian liên kết. Mặt khác, các ký hiệu là tên hàm dù sao cũng được giải quyết tại thời điểm liên kết. Ý nghĩa của một trình xác định lớp lưu trữ trên một hàm ( extern, static) chỉ ảnh hưởng đến khả năng hiển thị của nó và externlà mặc định, vì vậy externthực sự không cần thiết.

Tôi đề nghị loại bỏ extern, nó là không liên quan và thường được bỏ qua.


9
Sử dụng (void) trong C để chỉ ra rằng một hàm không có đối số. Trong C ++, trừ khi bạn đặc biệt cần mã của mình để biên dịch cả C và C ++, chỉ cần sử dụng ().
Keith Thompson

49

Trả lời nhanh: thay đổi int testlib()để int testlib(void)xác định rằng hàm không có đối số.

Một nguyên mẫu theo định nghĩa là một khai báo hàm chỉ định loại (các) đối số của hàm.

Một khai báo hàm không nguyên mẫu như

int foo();

là một khai báo kiểu cũ không chỉ định số lượng hoặc loại đối số. (Trước tiêu chuẩn ANSI C năm 1989, đây là loại khai báo hàm duy nhất có sẵn trong ngôn ngữ.) Bạn có thể gọi một hàm như vậy với bất kỳ số lượng đối số tùy ý nào và trình biên dịch không bắt buộc phải khiếu nại - nhưng nếu cuộc gọi không phù hợp với định nghĩa , chương trình của bạn có hành vi không xác định.

Đối với một hàm có một hoặc nhiều đối số, bạn có thể chỉ định loại của từng đối số trong khai báo:

int bar(int x, double y);

Các hàm không có đối số là một trường hợp đặc biệt. Về mặt logic, các dấu ngoặc rỗng sẽ là một cách tốt để xác định rằng một đối số nhưng cú pháp đó đã được sử dụng cho các khai báo hàm kiểu cũ, vì vậy ủy ban ANSI C đã phát minh ra một cú pháp mới bằng voidtừ khóa:

int foo(void); /* foo takes no arguments */

Một định nghĩa hàm (bao gồm mã cho những gì hàm thực sự làm) cũng cung cấp một khai báo . Trong trường hợp của bạn, bạn có một cái gì đó tương tự như:

int testlib()
{
    /* code that implements testlib */
}

Điều này cung cấp một tuyên bố không nguyên mẫu cho testlib. Theo định nghĩa, điều này cho trình biên dịch testlibkhông có tham số, nhưng như một khai báo, nó chỉ cho trình biên dịch testliblấy một số số và loại (các) đối số không xác định.

Nếu bạn thay đổi ()để (void)khai báo trở thành một nguyên mẫu.

Ưu điểm của một nguyên mẫu là nếu bạn vô tình gọi testlibbằng một hoặc nhiều đối số, trình biên dịch sẽ chẩn đoán lỗi.

(C ++ có các quy tắc hơi khác nhau. C ++ không có khai báo hàm kiểu cũ và dấu ngoặc đơn trống có nghĩa là hàm không có đối số. C ++ hỗ trợ (void)cú pháp để thống nhất với C. Nhưng trừ khi bạn đặc biệt cần mã của mình để biên dịch cả hai C và là C ++, có lẽ bạn nên sử dụng cú pháp trong ()C ++ và (void)cú pháp trong C.)


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.