Tại sao kích thước của một hàm trong C luôn là 1 byte?


87

Khi chúng tôi kiểm tra kích thước của một hàm đang sử dụng sizeof(), chúng tôi luôn nhận được 1 byte . 1 byte này biểu thị điều gì?

Câu trả lời:


80

Đó là một vi phạm ràng buộc và trình biên dịch của bạn nên chẩn đoán nó. Nếu nó biên dịch nó bất chấp điều đó, chương trình của bạn có hành vi không xác định [cảm ơn @Steve Jessop đã giải thích rõ về chế độ lỗi và xem câu trả lời của @Michael Burr để biết lý do tại sao một số trình biên dịch cho phép điều này]: Từ C11, 6.5.3.4./ 1:

Các sizeofnhà điều hành sẽ không được áp dụng cho một biểu thức có kiểu chức năng


11
Đó là một hạn chế, có nghĩa là trong một trình biên dịch phù hợp, nó được chẩn đoán. Nếu trình biên dịch vẫn biên dịch nó (đã chẩn đoán nó), thì hành vi là không xác định. Nếu trình biên dịch không chẩn đoán nó (ví dụ: gcc không có -pedantic), bạn có một trình biên dịch không phù hợp và mọi chương trình đều có hành vi không xác định.
Steve Jessop

1
Hành vi đặt nó vào cùng một danh mục với một tiện ích mở rộng GNU C, nhưng tôi không biết tại sao có người lại muốn hành vi đó, vì vậy tôi không biết tại sao các tác giả GNU lại cố gắng thêm nó vào.
Steve Jessop

1
@SteveJessop: Lưu ý rằng điều này thậm chí với -std=c11, không phải gnu11 . Đây là một phần mở rộng trình biên dịch thực sự kỳ lạ.
Kerrek SB

6
Ôi! Tôi đặt cược đó là để cho phép số học trên con trỏ hàm, cùng một cách mà sizeof(void)là 1 trong GNU C.
Steve Jessop

3
Về việc -std=c11: ai đó nên tham khảo các -std=c*tùy chọn cho Tiêu chuẩn quảng cáo. Họ không bật chế độ tuân thủ, họ chỉ vô hiệu hóa các tiện ích mở rộng có thể ngăn một chương trình đã được định dạng tốt biên dịch (chẳng hạn như typeoflà một từ khóa, vì một chương trình C được định dạng tốt có thể sử dụng nó làm tên biến, nhưng gcctheo mặc định sẽ từ chối điều đó ). Ngoài ra, để vô hiệu hóa các tiện ích mở rộng cho phép các chương trình không hợp lệ vượt qua mà không được chẩn đoán, bạn cần -pedantichoặc -pedantic-errors.
Steve Jessop

56

Đây không phải là hành vi không xác định - tiêu chuẩn ngôn ngữ C yêu cầu chẩn đoán khi sử dụng sizeoftoán tử với bộ chỉ định hàm (tên hàm) vì đó là một vi phạm ràng buộc đối với sizeoftoán tử.

Tuy nhiên, như là một phần mở rộng của ngôn ngữ C, GCC cho phép số học trên voidcon trỏ và con trỏ hàm, được thực hiện bằng cách coi kích thước của một voidhoặc một hàm là 1. Do đó, sizeofnhà điều hành sẽ đánh giá 1cho voidhoặc một chức năng với GCC. Xem http://gcc.gnu.org/onlineocs/gcc/Pointer-Arith.html#Pointer-Arith

Bạn có thể yêu cầu GCC đưa ra cảnh báo khi sử dụng sizeofvới các toán hạng này bằng cách sử dụng -pedantichoặc -Wpointer-arithcác tùy chọn đối với GCC. Hoặc làm cho nó một lỗi với -Werror=pointer-arith.


Logic của bạn là thiếu sót. C yêu cầu thông báo chẩn đoán cho một số, nhưng không phải tất cả UB. Bạn không thể nói rằng một cái gì đó đã xác định hành vi chỉ vì có một chẩn đoán.
MSalters

4
C yêu cầu chẩn đoán cho tất cả các vi phạm ràng buộc (5.1.1.3 Chẩn đoán trong C99 hoặc C11). Một ràng buộc (3.8 trong C99 / C11) là một "hạn chế, cả về cú pháp hoặc ngữ nghĩa, theo đó việc giải thích các yếu tố ngôn ngữ sẽ được diễn giải", điều này dường như nói rằng một cái gì đó không tuân theo các ràng buộc sẽ không thể được diễn giải .
Michael Burr

3
Và rõ ràng hơn - vi phạm ràng buộc không dẫn đến hành vi không xác định. Đó là một lỗi, giống như một lỗi cú pháp. Ví dụ, tiêu chuẩn nói, "nếu một yêu cầu" sẽ "hoặc" sẽ không "xuất hiện bên ngoài một ràng buộc bị vi phạm, hành vi đó là không xác định". Nếu vi phạm ràng buộc sẽ dẫn đến UB, tại sao tiêu chuẩn chỉ nói về "shalls" và "would nots" mà không có ràng buộc ở đây?
Michael Burr

3
Tôi thực sự không nói gì nhiều về UB ngoại trừ sizeofmột chức năng không phải là UB (mà tôi đã đề cập khá nhiều chỉ vì các câu trả lời khác nói rằng đó là UB). Nhưng có lẽ tôi đã nhầm lẫn điều đó vì cách tôi cấu trúc câu. Để rõ ràng hơn. sizeofmột chức năng không phải là UB (như một số câu trả lời đã tuyên bố). Đó là một sự vi phạm ràng buộc. Như vậy, nó yêu cầu một chẩn đoán. GCC cho phép nó như một phần mở rộng.
Michael Burr

2
@KerrekSB: OP không nhận được chẩn đoán vì có lẽ họ đang sử dụng GCC, cho phép sử dụng này như một phần mở rộng ngôn ngữ C.
Michael Burr

13

Nó biểu thị rằng người viết trình biên dịch đã quyết định giá trị là 1 thay vì khiến ma quỷ bay khỏi mũi bạn (thực sự, đó là một cách sử dụng không xác định khác của sizeofnó đã cho chúng ta biểu thức đó: "Bản thân trình biên dịch C PHẢI đưa ra chẩn đoán NẾU đây là yêu cầu đầu tiên kết quả chẩn đoán từ chương trình của bạn, và sau đó chính nó CÓ THỂ khiến ma quỷ bay khỏi mũi bạn (nhân tiện, có thể là thông báo chẩn đoán được ghi lại bằng văn bản) giống như nó CÓ THỂ đưa ra thêm chẩn đoán đối với những vi phạm thêm các quy tắc hoặc ràng buộc cú pháp (hoặc, cho vấn đề đó, vì bất kỳ lý do gì nó chọn). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Từ này có thuật ngữ tiếng lóng "quỷ mũi" cho bất cứ điều gì mà trình biên dịch quyết định làm để đáp ứng với một cấu trúc không xác định. 1là con quỷ mũi của trình biên dịch này cho trường hợp này.


@IlmariKaronen Mặc dù vậy, tôi sẽ phải thừa nhận rằng có lý do mà hầu hết các câu trả lời của tôi về C (và C ++) đều dựa trên các nguyên tắc ngôn ngữ-bất khả tri chung hoặc các nguyên tắc lịch sử như vậy. Trải nghiệm C của tôi gần với lịch sử tự thân :)
Jon Hanna

7

Như những người khác đã chỉ ra, sizeof () có thể lấy bất kỳ số nhận dạng hợp lệ nào, nhưng nó sẽ không trả về kết quả hợp lệ (một kết quả trung thực đúng và hợp lệ) cho các tên hàm. Hơn nữa, nó chắc chắn có thể, hoặc có thể không, dẫn đến hội chứng "quỷ không có mũi".

Nếu bạn muốn định cấu hình kích thước hàm chương trình của mình, hãy kiểm tra bản đồ trình liên kết, có thể tìm thấy trên thư mục kết quả trung gian (thư mục nơi mọi thứ được biên dịch thành .obj / .o hoặc nơi chứa hình ảnh / tệp thực thi kết quả). Đôi khi có một tùy chọn để tạo hoặc không tạo tệp bản đồ này ... nó phụ thuộc vào trình biên dịch / trình liên kết.

Nếu bạn muốn kích thước của một con trỏ đến một hàm, chúng đều có cùng kích thước, kích thước của một từ địa chỉ trên cpu của bạn.


1
Loại câu lệnh nào là "chắc chắn có thể có hoặc không" ??? Điều đó không đúng với mọi thứ theo nghĩa đen sao?
Kerrek SB

@KerrekSB có, nhưng ở đây nó có thể có hoặc có thể không làm bất cứ điều gì và vẫn nằm trong quy tắc. Đúng là một trình biên dịch có thể từ chối biên dịch hoặc không thể từ chối biên dịch int x = 1;nhưng chỉ một trong những điều đó được phép đối với trình biên dịch tuân thủ các tiêu chuẩn. Với sizeof()việc được áp dụng cho một hàm, nó có thể có hoặc không trả về một giá trị đã đặt, hoặc từ chối biên dịch hoặc trả về một giá trị ngẫu nhiên dựa trên bất kỳ giá trị nào trong một thanh ghi cụ thể tại thời điểm đó. Quỷ mũi theo nghĩa đen là không chắc, nhưng trong tiêu chuẩn chữ cái.
Jon Hanna

@kerrek Nó có thể đúng đối với bất cứ điều gì hoặc có thể không sai đối với bất cứ điều gì ... nhìn nó là mờ nhạt phi logic.
jpinto3912

1
Nếu bạn muốn biết kích thước của một con trỏ đến một hàm, hãy áp dụng sizeofcho một con trỏ tới một hàm.
alexis
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.