2012-01-23 33 views
11

Tôi không hoàn toàn chắc chắn nếu nó thực sự cần thiết để có nguyên mẫu cho các chức năng tĩnh trong C. Miễn là tôi không xuất các chức năng như vậy (tức là chúng không có liên kết bên ngoài), những gì lợi ích khác có thể cung cấp cho nó?nguyên mẫu cho các chức năng 'tĩnh'

Cảm ơn.

Trả lời

6

Ví dụ: nếu bạn cần đảm bảo rằng một hàm có một loại nhất định, nó có thể hữu ích.

Hãy xem xét điều này:

// Define how the functions should be defined. 
typedef void * jobfunc(void *); 

// Use case 
void addjob(jobfunc *); 

// Ensure they have the right type. Without this, you only get a warning 
// for addjob(job2) (see below) - with it, you get an error for the mismatch. 
static jobfunc job1; 
static jobfunc job2; 

// Define one job 
static void * job1(void * arg) { 
    return NULL; 
} 

// Define another job - accidentally wrong. 
static void * job2(int accidentally_wrong) { 
    return NULL; 
} 
+3

Tôi nghĩ rằng bằng cách sử dụng typedef như một số loại mẫu chức năng là thực hành khá mơ hồ, nó rất có thể chỉ gây nhầm lẫn cho người đọc. Ví dụ, tôi mất một thời gian để giải thích mã của bạn thực sự làm gì. Phản ứng tức thời nhưng không chính xác của tôi đối với mã là "aha - con trỏ hàm". – Lundin

+0

@Lundin Bạn đang ở ngay khi nó không bình thường. Nhưng nó thực hiện công việc của mình. Có lẽ kiểu trả về 'void *' đã thêm vào sự nhầm lẫn - như một ví dụ, tôi nên lấy một kiểu khác. Tuy nhiên, tôi không hiểu tại sao điều này lại quá bất thường - thật tuyệt vời để đảm bảo đúng loại và, ngoài khả năng đọc và nhầm lẫn do sự không rõ, tôi không thể thấy bất lợi. – glglgl

6

Nếu bạn muốn sử dụng chúng trước khi triển khai, bạn nên viết mẫu thử nghiệm.

Thông thường, bạn có thể thay đổi thứ tự của các hàm, nhưng điều gì sẽ xảy ra nếu bạn có 2 hàm tĩnh, gọi cho nhau?

+0

@Mark: Ví dụ: trình biên dịch cần biết chữ ký của hàm 'foo' là gì trước khi phân tích cú pháp cuộc gọi đến hàm' foo', để đảm bảo rằng lệnh gọi 'foo' đẩy các tham số chính xác và như vậy . –

+0

asaelr: bạn có thể xây dựng trên nhận xét của mình không? Bạn có ý gì khi 'sử dụng trước khi thực hiện'? – Mark

+0

như ouah đã viết, tôi có nghĩa là bạn có thể viết một hàm người gọi ở trên của hàm callee. – asaelr

3

Một (nhỏ) thuận tiện là nó sẽ cho phép bạn đặt các chức năng ở bất cứ đâu bạn thích trong tệp. Ví dụ, nếu bạn muốn đặt các hàm tiện ích vào cuối tập tin, bạn phải khai báo chúng.

Trường hợp bạn phải khai báo hàm của mình là khi bạn có hai hàm đệ quy hai lần, vì hàm được đặt đầu tiên trong tệp chưa thấy hàm khác.

4

Tuyên bố không có định nghĩa hàm static (chức năng này giống với chức năng extern) cho phép bạn gọi hàm trước khi hàm được xác định. Trong C, một định danh cho một hàm phải được khai báo trước khi nó có thể được sử dụng:

static void foo(void); 

void bar(void) 
{ 
    foo(); 
} 

static void foo(void) 
{ 
    ... 
} 
+0

Cảm ơn mọi người vì câu trả lời toàn diện! – Mark

8

Để trích dẫn một số cơ quan, Misra-C: 2004 quy tắc 8.1 thực thi nguyên mẫu cho các chức năng với mối liên hệ bên ngoài, mà còn đề cập đến mối liên kết nội bộ :

"Việc cung cấp mẫu thử cho chức năng có liên kết nội bộ là thực hành lập trình tốt".

Tôi coi đây là thực tiễn tốt vì nó làm cho phong cách mã hóa của bạn giữa các hàm liên kết bên trong/bên ngoài nhất quán. Và như những người khác đã đề cập trong câu trả lời của họ, nó là thuận tiện là tốt.

+1

Đây là một trong số ít quy tắc của MISRA mà tôi đồng ý. Tôi luôn đặt (ở trên cùng của tệp nguồn) các khai báo hàm 'static' của tất cả các hàm' static' được định nghĩa trong tệp nguồn. Đây là tài liệu hay về mã và API nội bộ. – ouah

0

Nếu bạn sẽ không khai báo hàm nguyên mẫu mã dưới đây sẽ có hiệu lực.

static int bar() 
{ 

}; 

int foo() 
{ 
    bar("asdf"); 
}; 

Và loại lỗi ẩn này có thể nguy hiểm. Kiểm tra phần "2 7 .2.2 Kiểm tra loại đối số chức năng" trong một lần nữa có thể là Nguyên tắc và Thực hành hữu ích Sử dụng C++ [Bjarne Stroustrup].

Các vấn đề liên quan