2008-09-18 64 views
41

Tôi đã nghe nói về một số phương pháp, nhưng không có phương pháp nào bị kẹt. Cá nhân tôi cố gắng tránh các loại phức tạp trong C và cố gắng chia chúng thành thành phần typedef.Làm thế nào để bạn đọc các khai báo C?

Tôi hiện đang phải đối mặt với việc duy trì một số mã cũ từ một 'lập trình viên ba sao', và tôi đang gặp khó khăn khi đọc một số mã *** [] [].

Làm thế nào để bạn đọc các khai báo C phức tạp?

+2

Mắt hoạt động ... Nhưng nếu bạn đang mắc kẹt sử dụng Windows, tôi cho rằng bạn có thể thử Người kể chuyện. – Shog9

+5

Vì vậy, "lập trình ba sao" có nghĩa là có ít nhất ba ngôi sao trong tất cả các loại mà ông tuyên bố? –

+3

khá nhiều, nó là một trường học cũ xúc phạm cho một lập trình c xấu – 1729

Trả lời

3

Quay lại khi tôi đang thực hiện C, tôi đã sử dụng chương trình có tên là "cdecl". Có vẻ như nó nằm trong Ubuntu Linux trong gói cutils hoặc cdecl, và nó có thể có sẵn ở nơi khác.

5

Một từ: cdecl

Damnit, bị đánh bại 15 giây!

+0

Xem nhận xét của tôi ở trên. Đối với '*** code [] []', nó trả về 'cú pháp lỗi' :-) Một trang hữu ích chết tiệt, mặc dù – Mawg

28

Bài viết này giải thích một 7 quy tắc tương đối đơn giản mà sẽ cho phép bạn đọc bất kỳ tuyên bố C, nếu bạn thấy mình muốn hoặc cần phải làm như vậy bằng tay: http://www.ericgiguere.com/articles/reading-c-declarations.html

  1. Tìm các định danh. Đây là điểm khởi đầu của bạn. Trên một tờ giấy, viết "khai báo nhận dạng là".
  2. Nhìn bên phải. Nếu không có gì ở đó, hoặc có dấu ngoặc đơn chính xác ")", hãy goto bước 4.
  3. Bạn hiện được định vị trên một dấu (mảng bên trái) hoặc mô tả hàm (dấu ngoặc đơn bên trái). Có thể có một chuỗi các chuỗi này, kết thúc bằng dấu ngoặc đơn chưa khớp hoặc phần cuối của trình khai báo (dấu chấm phẩy hoặc "=" để khởi tạo). Đối với mỗi mô tả như vậy, đọc từ trái sang phải:

    • nếu một mảng trống rỗng "[]", hãy viết "mảng"
    • nếu một mảng với kích thước, hãy viết "kích thước mảng của"
    • nếu hàm "()", viết "hàm trả về"

    Dừng tại dấu ngoặc đơn chưa khớp hoặc kết thúc của người khai báo, tùy điều kiện nào đến trước.

  4. Quay lại vị trí bắt đầu và nhìn sang trái. Nếu không có gì ở đó, hoặc có dấu ngoặc đơn bên trái "(", bước goto 6.
  5. Bạn hiện được định vị trên bộ mô tả con trỏ, "*". Có thể có một chuỗi ở bên trái, kết thúc bằng một dấu ngoặc đơn chưa được so khớp bên trái "(" hoặc bắt đầu của người khai báo. Đọc từ phải sang trái, cho mỗi bộ mô tả con trỏ viết "con trỏ tới". Dừng tại dấu ngoặc đơn chưa từng có hoặc bắt đầu của người khai báo, tùy theo cái nào là trước.
  6. Tại thời điểm này, bạn có biểu thức được lồng tiếng hoặc khai báo đầy đủ. Nếu bạn có biểu thức được ngoặc đơn, hãy xem đó là điểm xuất phát mới của bạn và quay lại bước 2.
  7. Viết xuống trình chỉ định loại. Dừng lại.

Nếu bạn đang sử dụng tốt với một công cụ, sau đó tôi đề nghị thứ hai để sử dụng chương trình cdecl: http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

1

cdecl cung cấp một giao diện dòng lệnh vì vậy hãy cho nó một thử:

ví dụ khác

explain int (*IMP)(ID,SEL) 
declare IMP as pointer to function (ID, SEL) returning int 

Tuy nhiên t ở đây là cả một chương về điều đó trong cuốn sách "C sâu bí mật", có tên là "tờ khai Unscrambling trong C.

Trân Friedrich

20

Tôi thường sử dụng những gì đôi khi được gọi là 'tay phải quy tắc chiều kim đồng hồ. Nó giống như sau:

  • Bắt đầu từ từ định danh.
  • Chuyển đến ngay bên phải của nó.
  • Sau đó di chuyển theo chiều kim đồng hồ và đến phía bên tay trái.
  • Di chuyển theo chiều kim đồng hồ và đến bên phải.
  • Thực hiện việc này miễn là bản khai báo chưa được phân tích đầy đủ.

Có thêm meta-quy tắc đó phải được đưa về chăm sóc:

  • Nếu có dấu ngoặc đơn, hoàn thành mỗi cấp độ của dấu ngoặc đơn trước khi chuyển ra ngoài.

Ở đây, 'đi' và 'di chuyển' ở đâu đó có nghĩa là đọc biểu tượng ở đó. Các quy tắc cho điều đó là:

  • * - con trỏ đến
  • () - chức năng trở
  • (int, int) - chức năng chụp hai ints và trở
  • int, char, vv - int, char vv
  • [] - mảng
  • [10] - mảng mười
  • v.v.

Vì vậy, ví dụ, int* (*xyz[10])(int*, char) được đọc như sau:

xyz là một mảng

mười

con trỏ đến

chức năng thực thi một int * và char và trả lại

một int *

+0

@sundar: tham chiếu rất đẹp! – Lazer

+0

@sundar: Bạn có thể mở rộng nó để bao gồm các mảng đa chiều và các con trỏ hàm không? Điều gì về 'extern char * const (* goop (char * b)) (int, long);'? (được chọn từ http://www.ericgiguere.com/articles/reading-c-declarations.html) – Lazer

0

giải pháp tự động là cdecl.

Nói chung, bạn khai báo biến theo cách bạn sử dụng. Ví dụ, bạn dereference một con trỏ p như trong:

 
char c = * p 

bạn khai báo nó trong một cách nhìn tương tự:

 
char * p; 

Cùng đi với con trỏ hàm lông. Hãy khai báo f để trở thành "con trỏ trỏ đến hàm trả về con trỏ", và khai báo bên ngoài chỉ là vui. Đó là một con trỏ đến một chức năng, vì vậy chúng tôi bắt đầu với:

 
extern * f(); 

nó trả về một con trỏ đến một int, vì vậy nơi nào đó ở phía trước có có

 
extern int * * f(); // XXX not quite yet 

Bây giờ là associativity có đúng không? Tôi không bao giờ có thể nhớ, do đó, sử dụng một số dấu ngoặc đơn.

 
extern (int *)(* f)(); 

Tuyên bố cách bạn sử dụng.

0

Đọc từ phải sang trái.

***code[][] 
  • mã số [] [] là một mảng multidimenstional
  • * Mã [] [] là một con trỏ mảng multidimenstional
  • ** mã số [] [] là một con trỏ mảng multidimenstional đến một con trỏ
  • *** mã số [] [] là một con trỏ mảng multidimenstional đến một con trỏ đến một con trỏ
0

Chỉ cần đi qua một phần chiếu sáng trong "The Development of the C Language ":

Đối với mỗi đối tượng thuộc loại như vậy, đã có cách đề cập đến đối tượng bên dưới: chỉ mục mảng, gọi hàm, sử dụng toán tử gián tiếp trên con trỏ. Lý do tương tự dẫn đến một cú pháp khai báo cho các tên phản ánh cú pháp biểu thức trong đó các tên thường xuất hiện.Như vậy,

int i, *pi, **ppi;

tuyên bố một số nguyên, một con trỏ đến một số nguyên, một con trỏ đến một con trỏ đến một số nguyên. Cú pháp của các khai báo này phản ánh quan sát rằng i, * pi, và ** ppi đều mang lại một kiểu int khi được sử dụng trong một biểu thức. Tương tự như vậy,

int f(), *f(), (*f)();

tuyên bố một hàm trả về một số nguyên, một hàm trả về một con trỏ đến một số nguyên, một con trỏ tới một hàm trả về một số nguyên;

int *api[10], (*pai)[10];

khai báo một mảng của con trỏ đến số nguyên, và một con trỏ đến một mảng các số nguyên. Trong tất cả các trường hợp này, việc khai báo một biến tương tự như cách sử dụng của nó trong một biểu thức có kiểu là một biến được đặt tên ở phần đầu của khai báo.

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