Tại sao sizeof int là sai, trong khi sizeof (int) là đúng?


96

Chúng ta biết rằng đó sizeoflà một toán tử được sử dụng để tính toán kích thước của bất kỳ kiểu dữ liệu và biểu thức nào, và khi toán hạng là một biểu thức, dấu ngoặc đơn có thể được bỏ qua.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

cách sử dụng đầu tiên sizeoflà sai, trong khi những cách sử dụng khác đúng.

Khi nó được biên dịch bằng gcc, thông báo lỗi sau sẽ được đưa ra:

main.c:5:9: error: expected expression before int

Câu hỏi của tôi là tại sao tiêu chuẩn C không cho phép loại hoạt động này. Sẽ sizeof intgây ra bất kỳ sự mơ hồ?


5
Điều buồn cười là không phải tất cả các biểu thức đều được chấp nhận mà không có dấu ngoặc đơn: try sizeof (int)a.
Fred Foo

2
@MikkelK: OP đang hỏi lý do đằng sau những câu trích dẫn tiêu chuẩn, anh ấy đã biết những câu trích dẫn được đề cập trong câu trả lời được đánh dấu.
Alok Save

2
@Lundin: sizeof +(int)ađã lợi thế hơn *&của thực sự biên soạn ;-)
Steve Jessop

2
@SteveJessop À đúng rồi, nó không phải là giá trị. Mặc dù nó đã được biên dịch trong Embarcadero C ++, nhưng thật kỳ lạ. Dù sao, tôi tin rằng chúng ta vừa mới tìm thấy một công dụng cho toán tử đơn nguyên +! Đó phải là lần đầu tiên trong lịch sử lập trình C :)
Lundin

2
@Lundin: Bạn vẫn phải cẩn thận với đơn nguyên +. Ví dụ: sizeof +(char)a == sizeof(int)do quảng cáo số nguyên, có lẽ ít bị lỗi hơn chỉ cần đặt trong dấu ngoặc đơn nếu có bất kỳ lo lắng nào về biểu thức bạn đang cố lấy kích thước. Vì vậy, tôi không chắc là tôi muốn đi xa như vậy để gọi nó là "một sử dụng", mặc dù tôi thừa nhận tôi đã sử dụng nó ...
Steve Jessop

Câu trả lời:


101

Những điều sau có thể không rõ ràng:

sizeof int * + 1

Đó là (sizeof (int*)) + 1, hoặc (sizeof(int)) * (+1)?

Rõ ràng ngôn ngữ C có thể đã đưa ra một quy tắc để giải quyết sự mơ hồ, nhưng tôi có thể tưởng tượng tại sao nó không bận tâm. Với ngôn ngữ như hiện tại, một chỉ định kiểu không bao giờ xuất hiện "trần trụi" trong một biểu thức và vì vậy không cần quy tắc để giải quyết xem thứ hai đó *là một phần của kiểu hay một toán tử số học.

Ngữ pháp hiện có đã giải quyết được sự mơ hồ tiềm ẩn của sizeof (int *) + 1. Nó là (sizeof(int*))+1, không phải sizeof((int*)(+1)) .

C ++ có một vấn đề tương tự cần giải quyết với cú pháp ép kiểu hàm. Bạn có thể viết int(0)và bạn có thể viết typedef int *intptr; intptr(0);, nhưng bạn không thể viết int*(0). Trong trường hợp đó, giải pháp là kiểu "naked" phải là một tên kiểu đơn giản, nó không thể chỉ là bất kỳ id kiểu cũ nào có thể có khoảng trắng trong đó hoặc dấu chấm câu ở cuối. Có lẽ sizeofcó thể đã được xác định với cùng một hạn chế, tôi không chắc.


1
C ++ có new int*(X)điều này sẽ không rõ ràng nếu C ++ không chỉ định rằng toán tử mới lấy chuỗi dài nhất có thể là một kiểu. Vì vậy, trong C ++, họ có thể tạo ra điều tương tự với sizeof, tôi đoán vậy. Nhưng trong C ++, bạn có thể nói rằng sizeof int()sau đó sẽ không rõ ràng (kiểu hoặc giá trị được khởi tạo int?).
Johannes Schaub - litb

@ JohannesSchaub-litb: Mmm, vì vậy có lẽ khi đó C ++ có thể nói rằng kiểu được ưu tiên hơn nếu có thể phân tích cú pháp, nếu không thì đó là một biểu thức. Sự mơ hồ sẽ được giải quyết nhưng sizeof int()sẽ không thành công ("không operator()cho size_t"), mà tôi mong đợi sẽ không được hoan nghênh!
Steve Jessop

32

Từ tiêu chuẩn C99

6.5.3.4.2
Các sizeofnhà điều hành mang lại kích thước (tính theo byte) của toán hạng của nó, có thể là một biểu thức hoặc tên trong ngoặc của một loại.

Trong trường hợp của bạn intkhông phải là biểu thức cũng như tên trong ngoặc đơn.


10
Tôi không hiểu tại sao điều này lại nhận được 7 lượt ủng hộ. Giống như ba câu trả lời đã bị xóa, nó chỉ lặp lại quy tắc thay vì giải thích tại sao quy tắc tồn tại.
Fred Foo

7
@larsmans, vâng, tôi đồng ý với bạn. Mặc dù nó tiếp tục lặp lại quy tắc, nhưng ít nhất, nó cung cấp một phần cho phép đọc.
Yishu Fang

3
@larsmans Nếu chúng tôi bắt đầu cố gắng biện minh cho mọi quyết định được đưa ra trong C99, chúng tôi sẽ ở đây cả năm. Trích dẫn tiêu chuẩn là một cách tốt như bất kỳ cách nào để kết thúc cuộc thảo luận này.
Perry

1
@Perry: nếu bạn không thích loại câu hỏi này, bạn có thể bỏ phiếu để đóng câu hỏi dưới dạng tranh luận.
Fred Foo

4
Là một người không học C ++, ngay cả tôi cũng hiểu câu trả lời này, nhưng không chắc vấn đề là gì nếu bạn có thể đọc và hiểu tiếng Anh.
Kev

6

Có hai cách để sử dụng toán tử sizeof trong C. Cú pháp như sau:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Bất cứ khi nào bạn sử dụng một kiểu làm toán hạng, bạn phải có dấu ngoặc đơn, theo định nghĩa cú pháp của ngôn ngữ. Nếu bạn sử dụng sizeof trên một biểu thức, bạn không cần dấu ngoặc đơn.

Tiêu chuẩn C đưa ra một ví dụ như vậy về nơi bạn có thể muốn sử dụng nó trên một biểu thức:

sizeof array / sizeof array[0]

Tuy nhiên, vì lợi ích của tính nhất quán và để tránh các lỗi liên quan đến quyền ưu tiên của toán tử, cá nhân tôi khuyên bạn nên luôn sử dụng () bất kể tình huống nào.


@ JohannesSchaub-litb Tôi đồng ý rằng nó không cung cấp bất kỳ cơ sở lý luận nào về cách hội đồng tiêu chuẩn C lý luận khi họ chỉ định tiêu chuẩn C90. Bạn sẽ phải hỏi họ ... Nó trả lời mà không có bất kỳ lý do nào được cung cấp, tuy nhiên, C không cho phép nó vì cú pháp như được chỉ định trong 6.5.3. OP dường như cũng không biết về sự khác biệt giữa sizeof expressionsizeof(type), điều này được giải thích trong câu trả lời này.
Lundin

(Đối với hồ sơ, tôi đã chỉ cần đọc cả lý do cơ bản C90 và C11 và không cung cấp bất kỳ lời giải thích.)
Lundin

Tôi nghi ngờ rằng không có lý do cần thiết cho nó, đó chỉ là cách các nhà thiết kế C ban đầu quyết định làm điều đó. Có lẽ nó đã giúp mọi thứ dễ dàng hơn cho trình phân tích cú pháp ban đầu. Tôi đã định đăng một câu trả lời về thực tế là typedef và các biến chia sẻ cùng một không gian tên, nhưng điều đó không loại trừ việc cho phép cú pháp đầu tiên; nó chỉ cần các quy tắc phân tích cú pháp để nói rằng nó thích biến khi không có parens, thích loại khi có và một trong hai dạng có thể được sử dụng khi tên rõ ràng. Vì không cần phải thay đổi nó, các ủy ban tiêu chuẩn đã để nó yên.
Barmar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.