2012-01-08 32 views
31

Trong C++, tôi có xu hướng bỏ qua tên của thông số trong một số trường hợp. Nhưng trong C, tôi gặp lỗi khi tôi bỏ qua tên của tham số.bị bỏ qua, C++ và C

Đây là mã:

void foo(int); //forward-decl, it's OK to omit the parameter's name, in both C++ and C 

int main() 
{ 
    foo(0); 
    return 0; 
} 

void foo(int) //definition in C, it cannot compile with gcc 
{ 
    printf("in foo\n"); 
} 

void foo(int) //definition in C++, it can compile with g++ 
{ 
    cout << "in foo" << endl; 
} 

Tại sao vậy? Tôi không thể bỏ qua tên của tham số trong định nghĩa hàm C?

+2

Viết file nguồn đa ngôn ngữ là (rất) công việc khó khăn. Tôi đề nghị bạn giữ từng tệp nguồn duy nhất trong một ngôn ngữ duy nhất. – pmg

+0

@pmg, cảm ơn lời khuyên của bạn,:) – Alcott

+0

Nhưng nếu bạn muốn một cái gì đó để biên dịch trong cả C và C++, không cần phải viết các hàm riêng biệt để sử dụng 'printf' và' str :: cout'. 'printf' hoạt động cho cả hai ngôn ngữ. Tôi muốn recomment chống lại bằng cách sử dụng hai chức năng có thể được viết là một, vì khả năng rằng chức năng của họ có thể không giống nhau. –

Trả lời

33

Không, trong C bạn không thể bỏ qua số nhận dạng cho các tham số trong định nghĩa hàm.

chuẩn

Các C99 nói:

[6.9.1.5] Nếu declarator bao gồm một danh sách loại tham số, khai của mỗi tham số bao gồm một định danh, trừ trường hợp đặc biệt của một danh sách tham số bao gồm một tham số loại void, trong trường hợp đó, không phải là số nhận dạng. Không danh sách khai báo phải tuân theo.

C++ 14 tiêu chuẩn nói:

[8.3.5.11] Một định danh có thể tùy chọn được cung cấp như một tham số tên; nếu có trong một định nghĩa hàm, nó đặt tên một tham số (đôi khi được gọi là "đối số chính thức"). [Lưu ý: Trong đó, tham số tên cũng là tùy chọn trong chức năng các định nghĩa và tên được sử dụng cho một tham số trong tờ khai khác nhau và định nghĩa của một hàm không nhất thiết phải giống nhau.]

+0

Vì vậy, một tên biến được gọi là một định danh? –

+5

@ Mr.TAMER: Tất cả các tên biến là số nhận dạng, nhưng một số số nhận dạng không phải là tên biến. –

+0

@DietrichEpp: Tôi hiểu, cảm ơn :). Với một tìm kiếm nhanh tôi tìm thấy [this] (http://msdn.microsoft.com/en-us/library/565w213d.aspx). –

4

Bạn có thể bỏ qua tên tham số trong mẫu thử nghiệm chức năng, nhưng bạn phải khai báo nó trong thực hiện hàm. Ví dụ, đây biên dịch và chạy tốt thuộc GCC 4.6.1

void foo(int, int); 

void foo(int value, int secondValue) 
{ 
    printf("In foo with value %d and %d!\n", value, secondValue); 
} 

int main(int argc, char **argv) 
{ 
    foo(10, 15); 
    return 0; 
} 

Đầu ra: In foo with value 10 and 15!

Là tại sao (trừ vì các tiêu chuẩn nói như vậy): C++ cho phép bạn gọi một chức năng mà không sử dụng tất cả các đối số, trong khi C thì không. Nếu bạn không cung cấp tất cả các đối số cho hàm trong C, thì trình biên dịch sẽ ném error: too few arguments to function 'foo'

+4

C++ * không * cho phép bạn bỏ qua các đối số trong một cuộc gọi trừ khi các tham số tương ứng có các giá trị mặc định. Và trong trường hợp đó, các giá trị mặc định được truyền hoàn toàn, và hàm phải cung cấp tên cho các đối số nếu nó tham chiếu đến các giá trị của chúng. Sự khác biệt là có nhiều trường hợp trong C++, nơi nó có ý nghĩa đối với một hàm bỏ qua một trong các tham số của nó. –

15

Lý do là đó là những gì các tiêu chuẩn ngôn ngữ tương ứng nói, nhưng có một lý do cho sự khác biệt.

Nếu bạn không cung cấp tên cho thông số, thì hàm không thể tham chiếu đến thông số đó.

Trong C, nếu một hàm bỏ qua một trong các tham số của nó, nó thường có ý nghĩa chỉ để loại bỏ nó khỏi khai báo và định nghĩa, và không vượt qua nó trong bất kỳ cuộc gọi nào. Một ngoại lệ có thể là một hàm gọi lại, trong đó tập hợp các hàm tất cả phải cùng loại nhưng không phải tất cả chúng đều nhất thiết phải sử dụng các tham số của chúng. Nhưng đó không phải là một kịch bản rất phổ biến. Trong C++, nếu hàm xuất phát từ một hàm được định nghĩa trong một số lớp cha, nó phải có cùng chữ ký với cha mẹ, ngay cả khi hàm con không sử dụng cho một trong các giá trị tham số.

(Lưu ý rằng điều này không liên quan đến tham số mặc định; nếu tham số trong C++ có giá trị mặc định, người gọi không phải chuyển nó một cách rõ ràng, nhưng định nghĩa hàm vẫn phải cung cấp tên nếu nó tham khảo nó.)

5

Ở cấp độ hoàn toàn thực tế, tôi đã giải quyết vấn đề này hàng ngày. Giải pháp tốt nhất cho đến nay là sử dụng bộ xử lý trước. tập tin tiêu đề chung của tôi chứa:

//------------------------------------------------------------------------- 
// Suppress nuisance compiler warnings. Yes, each compiler can already 
// do this, each differently! VC9 has its UNREFERENCED_PARAMETER(), 
// which is almost the same as the SUPPRESS_UNUSED_WARNING() below. 
// 
// We append _UNUSED to the variable name, because the dumb gcc compiler 
// doesn't bother to tell you if you erroneously _use_ something flagged 
// with __attribute__((unused)). So we are forced to *mangle* the name. 
//------------------------------------------------------------------------- 
#if defined(__cplusplus) 
#define UNUSED(x)  // = nothing 
#elif defined(__GNUC__) 
#define UNUSED(x)  x##_UNUSED __attribute__((unused)) 
#else 
#define UNUSED(x)  x##_UNUSED 
#endif 

Một ví dụ về việc sử dụng các UNUSED là:

void foo(int UNUSED(bar)) {} 

Đôi khi bạn thực sự cần phải tham khảo các thông số, ví dụ như trong một assert() hoặc tuyên bố gỡ lỗi. Bạn có thể làm như vậy qua:

#define USED_UNUSED(x) x##_UNUSED // for assert(), debug, etc 

Ngoài ra, sau đây là hữu ích:

#define UNUSED_FUNCTION(x) inline static x##_UNUSED // "inline" for GCC warning 
#define SUPPRESS_UNUSED_WARNING(x) (void)(x) // cf. MSVC UNREFERENCED_PARAMETER 

Ví dụ:

UNUSED_FUNCTION(int myFunction)(int myArg) { ...etc... } 

và:

void foo(int bar) { 
#ifdef XXX 
    // ... (some code using bar) 
#else 
    SUPPRESS_UNUSED_WARNING(bar); 
#endif 
} 
+1

Đây là trễ hai ngày. Tôi hy vọng là nó không * không sử dụng * ful. –

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