2015-05-31 24 views
25

Chương trình sau in cùng một số hai lần trên gcc 4.8.2:Dấu ngoặc đơn có tạo sự khác biệt khi xác định kích thước của mảng không?

#include <stdio.h> 

int main() 
{ 
    char a[13]; 
    printf("sizeof a is %zu\n", sizeof a); 
    printf("sizeof(a) is %zu\n", sizeof(a)); 
} 

Theo this reddit post, gcc không phải là tiêu chuẩn tuân thủ QTI trong lĩnh vực này, bởi vì một biểu thức trong ngoặc đơn không nằm trong danh sách các trường hợp ngoại lệ khi sự phân rã mảng-con trỏ không xảy ra.

Anh chàng này có đúng không? Dưới đây là các tiêu chuẩn có liên quan quote:

Trừ khi nó là toán hạng của sizeof điều hành hoặc & toán tử đơn hạng, hoặc là một chuỗi ký tự chữ sử dụng để khởi tạo một mảng của kiểu nhân vật, hoặc là một chuỗi rộng đen được sử dụng để khởi tạo một mảng với kiểu phần tử tương thích với wchar_t, một giá trị có loại 'mảng kiểu' được chuyển đổi thành một biểu thức có loại 'con trỏ để nhập' trỏ đến thành viên ban đầu của đối tượng mảng và không phải là một lvalue .

Chỉ cần được rõ ràng, ông lập luận rằng (a) nên kích hoạt mảng-to-con trỏ sâu, bởi vì dấu ngoặc đơn được không nằm trong danh sách trên (sizeof điều hành, unary & điều hành, chuỗi chữ như initializer).

+7

Không, anh chàng đó bị nhầm lẫn nghiêm trọng –

+1

Nói cách riêng của mình, tôi đồng ý với * bị nhầm lẫn * – chqrlie

+1

Tôi chưa xử lý công cụ này trong khoảng 15 năm, nhưng tôi chắc chắn đang nhớ lại một kịch bản, tôi nghĩ , 'sizeof' trong đó sự hiện diện hoặc vắng mặt của dấu ngoặc đơn là đáng kể - được xác định nếu bạn đang lấy kích thước của con trỏ hoặc kích thước của phần tử, hoặc một cái gì đó tương tự. –

Trả lời

24

Cho dù dấu ngoặc đơn dường như dư thừa ảnh hưởng đến ngữ nghĩa của chương trình là một vấn đề tồn tại lâu dài trong tiêu chuẩn C mà vẫn chưa được giải quyết thỏa đáng.

Người ta thường tuyên bố rằng ((void*)0) về mặt kỹ thuật không phải là hằng số con trỏ null, vì không có quy tắc nào cho biết hằng số con trỏ null được gắn ngoặc là hằng số con trỏ null.

Một số trình biên dịch gặp lỗi cho char s[] = ("abc");, bởi vì trong khi một mảng ký tự có thể được khởi tạo từ một chuỗi ký tự, quy tắc đó không bao gồm các chuỗi ký tự chuỗi được lồng.

Có nhiều ví dụ tương tự. Bạn đã tìm thấy một trong số họ.

Từ những gì tôi có thể nói, sự đồng thuận về cơ bản là quy tắc nên là những gì C++ làm, nhưng những gì C không bao giờ được chính thức thông qua.C++ làm cho một biểu thức được lồng hàm có chức năng tương đương với biểu thức không được đặt dấu ngoặc đơn, với một vài ngoại lệ được khai báo rõ ràng. Điều này sẽ bao gồm tất cả những vấn đề đó cùng một lúc. Vì vậy, về mặt kỹ thuật, anh chàng này có thể được coi là chính xác, nhưng nó là một giải thích quá nghiêm ngặt của tiêu chuẩn mà không ai thực sự theo, vì nó phổ biến kiến ​​thức rằng tiêu chuẩn chỉ đơn giản là bị lỗi ở đây.

+1

Thật tệ khi người ta không thể chỉ đơn giản là kiểm tra nếu một định danh đề cập đến một con trỏ hoặc một mảng, làm cho lỗi 'sizeof (argv)' dễ bị lỗi. Nó sẽ còn tệ hơn nếu 'sizeof (argv)' và 'sizeof argv' được đánh giá thành một thứ khác. Điều thực sự cần thiết là toán tử a'countof (a) 'đánh giá số lượng các phần tử của một mảng và đưa ra một lỗi thời gian biên dịch khi áp dụng cho một mảng không. – chqrlie

+0

@chqrlie Tôi muốn có các khối xây dựng cần thiết để tạo 'countof' (tôi thường thấy nó có tên là' LENGTHOF', nhưng cả hai đều hoạt động). Với '_Generic' của C11, tất cả những gì còn thiếu, tôi nghĩ, giống như' decltype' của C++ 11. Nếu chúng ta có điều đó, chúng ta có thể xác minh tĩnh rằng kiểu 'argv' khác với' & * argv'. – hvd

+0

Tôi thấy 'LENGTHOF (a)' ít hấp dẫn hơn vì sự nhầm lẫn tiềm ẩn giữa độ dài của chuỗi và kích thước của mảng byte tương ứng. Tôi đồng ý rằng các công cụ sẽ đủ, chẳng hạn như: 'typeof (a)! = Typeof (& * (a))' – chqrlie

21

Từ C99, 6.5.1, trên biểu thức trong ngoặc đơn:

loại và giá trị của nó là giống hệt với các biểu hiện unparenthesized.

Thoạt nhìn, nó sẽ xuất hiện rằng đây mâu thuẫn với các danh sách ngoại lệ bạn đang đề cập đến (6.3.2.1):

Trừ khi nó là toán hạng của sizeof điều hành hoặc unary & điều hành, hoặc là một chuỗi chữ sử dụng để khởi tạo một mảng, một biểu thức có kiểu "mảng của kiểu" được chuyển thành một biểu với kiểu "con trỏ để gõ" ...

Tuy nhiên, danh sách này là trong bối cảnh của toán tử/toán hạng; dấu ngoặc đơn dường như không được coi là một toán tử (dựa trên sự phân loại được ngụ ý bởi cấu trúc của phần 6.5).

+0

Bạn có thể liên kết trực tiếp đến phần nhờ vào một số linh hồn dũng cảm đã dành nhiều giờ chuyển đổi tài liệu pdf sang html: http://www.iso-9899.info/n1256.html#6.5.1p5, http: // www. iso-9899.info/n1256.html#6.3.2.1p3 ... hoặc cho C11: http://www.iso-9899.info/n1570.html#6.5.1p5, http: //www.iso-9899 .info/n1570.html # 6.3.2.1p3 – Sebivor

+1

C11 dường như chỉ cho phép _type-name_ trong phiên bản được cha mẹ hóa (6.5.3 # 1). Về điều này, một phiên bản với dấu ngoặc đơn quanh một _unary-expression_ sẽ cú pháp là phiên bản không được minh bạch với dấu ngoặc đơn là một phần của _unary-expression_. Làm cho công việc của trình biên dịch không dễ dàng hơn. Chỉnh sửa: tương tự cho C99. – Olaf

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