2013-08-24 2 views
10

Tôi không quen thuộc với khai báo hàm kiểu K & R.Khai báo hàm C trong K & R

Biên dịch sau đây, với cảnh báo (chỉ liên quan đến giá trị trả về của chính quá -Wall) nhưng loại dữ liệu của biến được sử dụng là gì?

main(a, b, c, d){ 
    printf("%d", d); 
} 

foo(a, b){ 
    a = 2; 
    b = 'z'; 
} 

Nếu điều này được yêu cầu trước, vui lòng cung cấp liên kết trong phần nhận xét. Tôi không thể tìm thấy một cái gì đó tương tự.

Sửa

Tôi vừa bắt gặp một mã C obfuscated, trong đó sử dụng những.
Nhưng tôi có thể đảm bảo với bạn, tôi sẽ không sử dụng cú pháp như vậy trong lập trình C.

+2

Cảnh báo bạn đang nhận được là gì? Sẽ rất có ích khi cố gắng trả lời câu hỏi của bạn. – Glenn

+0

@Glenn xin lỗi không có cảnh báo nào liên quan đến loại tiền thưởng – P0W

+0

: Hãy thử gọi 'foo (" this "," should "," work ")'. – nneonneo

Trả lời

19

"K & R C" dùng để chỉ ngôn ngữ được xác định bằng ấn bản đầu tiên năm 1978 của Kernighan & Sách của Ritchie "Ngôn ngữ lập trình C".

Trong K & R (tức là, pre-ANSI) C, các thực thể thường có thể được khai báo mà không có loại rõ ràng và sẽ mặc định là loại int. Điều này trở lại ngôn ngữ tổ tiên của C, B và BCPL.

main(a,b,c,d){ 
    printf("%d", d); 
} 

Đó là gần tương đương với:

int main(int a, int b, int c, int d) { 
    printf("%d", d); 
} 

Cú pháp cũ vẫn hợp pháp nhưng nưa trong ANSI C (1989) và ISO C (1990), nhưng tiêu chuẩn 1999 ISO C bỏ " quy tắc int "ngầm định (trong khi vẫn giữ cú pháp khai báo và định nghĩa kiểu cũ).

Lưu ý rằng tôi đã nói số đó là gần tương đương. Về cơ bản nó giống nhau khi được xem như một định nghĩa, nhưng như một tuyên bố nó không cung cấp thông tin kiểu tham số. Với định nghĩa kiểu cũ, một cuộc gọi với số sai hoặc các loại đối số không cần được chẩn đoán; nó chỉ là hành vi không xác định. Với một nguyên mẫu có thể nhìn thấy, các đối số không khớp sẽ kích hoạt một chẩn đoán thời gian biên dịch - và, khi có thể, các đối số được chuyển đổi hoàn toàn thành kiểu tham số.

Và vì đây là định nghĩa của main, có một vấn đề khác. Tiêu chuẩn chỉ chỉ định hai biểu mẫu cho main (một đối tượng không có đối số và một biểu mẫu có hai đối số, argcargv). Việc triển khai có thể hỗ trợ các biểu mẫu khác, nhưng một với bốn đối số int không thể là một trong số chúng. Do đó, hành vi của chương trình không được xác định. Trong thực tế, có khả năng là d sẽ có một số giá trị rác trên cuộc gọi ban đầu.(Và có, một cuộc gọi đệ quy để main được phép trong C, nhưng hầu như không bao giờ là một ý tưởng tốt.)

foo(a,b){ 
    a = 2; 
    b = 'z'; 
} 

này gần như tương đương với:

int foo(int a, int b) { 
    a = 2; 
    b = 'z'; 
} 

(Và lưu ý rằng 'z' là loại int, không loại char)

Và một lần nữa, hình thức cũ không cung cấp cho bạn kiểm tra kiểu tham số, do đó, một cuộc gọi như:.

foo("wrong type and number of arguments", 1.5, &foo); 

không cần chẩn đoán.

Điểm mấu chốt: Thật hữu ích khi biết K & các khai báo và định nghĩa hàm kiểu R hoạt động như thế nào. Vẫn còn mã cũ sử dụng chúng, và chúng vẫn còn hợp pháp (nhưng đã lỗi thời) ngay cả trong C2011 (mặc dù không có quy tắc "int ngầm"). Nhưng có rất gần như không có lý do tốt để viết mã sử dụng chúng (trừ khi bạn đang mắc kẹt bằng cách sử dụng một trình biên dịch rất cũ, nhưng đó là hiếm và trở nên hiếm hơn.)

Nhưng tôi có thể đảm bảo với bạn, tôi sẽ không sử dụng cú pháp như vậy trong lập trình C.

Tuyệt vời!

3

Trong C89, loại biến mặc định là int: được xác định là int ngầm. Quy tắc này đã bị thu hồi trong C99.

Trong ví dụ của bạn, nó được biên dịch như:

main(int a,int b,int c,int d){printf("%d", d);} 

foo(int a,int b){a=2; b='z';} 
+3

Vâng, gần như vậy. Trên thực tế, nó được biên dịch thành 'chính (a, b, c, d) int a, b, c, d;'. Sự khác biệt là tinh tế, nhưng với cú pháp K & R, bạn có thể làm những điều ngu ngốc như gọi bất kỳ chức năng nào với bất kỳ số lượng và loại tham số nào mà không có cảnh báo (xem, ví dụ: http://stackoverflow.com/q/18202232/1204143) – nneonneo

+0

Bất kỳ biện minh nào cho 'foo (a, b, c) {printf ("% s-% s-% s ", a, b, c); } chính (a, b, c, d) {foo ("này", "không nên", "công việc");} 'Nó chỉ hoạt động. – P0W

+0

@ P0W Đoạn mã của bạn được phân tách khi tôi cố biên dịch và chạy nó. Nó đã làm việc cho bạn? – aymericbeaumet

3

Tham số mặc định là kiểu int trong C và khoảng K cú pháp & R xin vui lòng có một cái nhìn herehere.

6

Trong K & Định nghĩa hàm kiểu R kiểu tham số được chỉ định bởi một bộ khai báo chuyên dụng được đặt giữa chính hàm "chữ ký" và thân hàm thực tế. Ví dụ, định nghĩa hàm này

void foo(a, b, c) 
double a; 
char b; 
{ 
    ... 
} 

sử dụng thông số của loại double, charint. Điều này thực sự là ở đâu và làm thế nào quy tắc "int tiềm ẩn" đi vào chơi: vì tham số c không được đề cập trong danh sách khai báo ở trên, nó được giả định là có loại int. Lưu ý các chi tiết quan trọng, mà tôi tin là không đủ rõ ràng bởi các câu trả lời khác: tham số c có loại int không phải vì loại bị thiếu trong danh sách tham số chức năng, mà là vì nó không được đề cập trong trình tự khai báo theo hàm "chữ ký" (trước phần thân hàm). Trong K & Kiểu khai báo kiểu R luôn bị thiếu trong danh sách tham số hàm (đó là tính năng xác định của khai báo K & R), nhưng nó không có nghĩa là tất cả tham số được giả định là loại int.

P.S. Lưu ý rằng C99 vẫn hỗ trợ các khai báo kiểu K & R, nhưng vì C99 cấm quy tắc "int ngầm", nó yêu cầu bạn đề cập đến tất cả các tham số chức năng trong danh sách khai báo đó sau hàm "chữ ký". Ví dụ trên sẽ không biên dịch trong C99 vì lý do đó. int c phải được thêm vào danh sách kê khai.

+0

+1 Cảm ơn bạn đã làm rõ lần cuối. Bạn có thể đưa ra một ví dụ trong đó 'int' không được giả định theo mặc định? – P0W

+0

@ P0W: Tôi không chắc chắn ý bạn là gì. Những gì tôi đang nói trong câu trả lời của tôi là trong ví dụ trên 'b' KHÔNG được giả định là' int' chỉ vì kiểu của nó bị thiếu trong danh sách tham số hàm. Để xác định loại 'b', thay vì nhảy đến kết luận ngay lập tức, trình biên dịch sẽ tiếp tục xem xét thêm. Nó sẽ phát hiện khai báo 'char b' và nhận ra rằng' b' được cho là một 'char'. – AnT