2012-10-24 41 views
11

Giả sử tôi có cấu trúc sau:Việc khởi tạo các cấu trúc có đảm bảo xóa các vùng đệm không bằng không?

typedef struct 
{ 
    unsigned field1 :1; 
    unsigned field2 :1; 
    unsigned field3 :1; 
} mytype; 

3 bit đầu tiên sẽ có thể sử dụng nhưng sizeof(mytype) sẽ trở lại 4 có nghĩa là 29 bit của padding. Câu hỏi của tôi là, được các bit đệm đảm bảo theo tiêu chuẩn là không khởi tạo bởi tuyên bố:

mytype testfields = {0}; 

hay:

mytype myfields = {1, 1, 1}; 

như vậy mà nó an toàn để thực hiện các memcmp() sau trên giả định rằng bit 4..29 sẽ bằng không và do đó sẽ không ảnh hưởng đến so sánh:

if (memcmp(&myfields, &testfields, sizeof(myfields)) == 0) 
    printf("Fields have no bits set\n"); 
else 
    printf("Fields have bits set\n"); 

Trả lời

11

Có và không. Các tiêu chuẩn thực tế, C11, quy định cụ thể:

Nếu một đối tượng có thời gian lưu trữ tĩnh hoặc chủ đề không phải là khởi tạo một cách rõ ràng, sau đó:

  • ....

  • nếu nó là tổng hợp, mọi thành viên được khởi tạo (đệ quy) theo các quy tắc này và mọi phần đệm được khởi tạo thành 0 bit;

Vì vậy, điều này chỉ giữ cho các đối tượng lưu trữ tĩnh, ở chế độ xem đầu tiên. Nhưng sau đó nó nói thêm:

Nếu có ít initializers trong một danh sách cú đúp kín hơn có là những yếu tố hoặc thành viên của một tổng hợp, hoặc các ký tự ít trong một chuỗi đen sử dụng để khởi tạo một mảng của được biết đến kích thước hơn có là các phần tử trong mảng, phần còn lại của tổng hợp sẽ là được khởi tạo hoàn toàn giống với các đối tượng có thời gian lưu trữ tĩnh là .

Điều này có nghĩa là đệm bên trong cấu trúc con không được khởi tạo rõ ràng là không được khởi tạo bằng bit.

Tóm lại, một số phần đệm trong cấu trúc được đảm bảo là không được khởi tạo bằng bit, một số thì không. Tôi không nghĩ rằng một sự nhầm lẫn như vậy là có chủ ý, tôi sẽ gửi một báo cáo lỗi cho việc này.

Phiên bản cũ hơn không có gì cả. Vì vậy, với hầu hết các trình biên dịch hiện tại, bạn phải cẩn thận hơn, vì chúng chưa thực hiện C11. Nhưng AFAIR, clang đã làm thay mặt đó.

Cũng lưu ý rằng điều này chỉ giữ để khởi tạo. Đệm không nhất thiết được sao chép khi gán.

+2

+1, thú vị Tôi đã không nhận thức được sự thay đổi này. – ouah

+4

Tôi nghĩ bạn nên thêm phần đầu của đoạn C11 * Nếu một đối tượng có thời lượng lưu trữ tự động không được khởi tạo một cách rõ ràng, giá trị của nó không xác định. Nếu một đối tượng có thời gian lưu trữ tĩnh hoặc luồng không được khởi tạo một cách rõ ràng, thì: * Điều này không đảm bảo phần đệm trong 'mytype testfields = {0};' được đặt thành '0'. – ouah

+0

@ouah, trên thực tế có vẻ như là một lỗ hổng, bạn nói đúng. Tôi không nghĩ rằng nó là dự định, vì vậy tôi sẽ giải thích thêm một chút. Điểm tốt. –

6

Chuẩn C99 không chỉ định bảng bit ding sẽ được đặt thành 0. Trong thực tế, nó đặc biệt đề cập rằng các giá trị của bất kỳ bit đệm nào không được chỉ định, do đó đệm không cần phải được sao chép trong một nhiệm vụ.

Footnote 51 đến 6.2.6.1 (6) (n1570):

Vì vậy, ví dụ, giao cấu trúc không cần phải sao chép bất kỳ bit đệm.

Tiêu chuẩn C2011 mới - nhờ Jens Gustedt để chia sẻ kiến ​​thức đó - xác định rằng bit đệm trong đối tượng của thời gian tĩnh hoặc lưu trữ chủ đề mà không cần khởi động rõ ràng được khởi tạo vào 0.

Có vẫn không có bảo đảm cho nhiệm vụ .

+2

Hmm, thay vào đó gợi ý rằng 'memcmp()' sẽ là một cách không an toàn để so sánh bất kỳ cấu trúc nào có đệm trong nó mặc dù phải không? – Benj

+0

@Benj Có, 'memcmp' không an toàn do hiệu ứng đệm. Mặc dù các bit đệm không được sử dụng, nhưng bạn * hợp pháp * không có quyền truy cập vào nó. Vì vậy, nó không nên quan trọng cho dù cách tiêu chuẩn nhiệm vụ padding hay không. –

+0

@KingsIndian: Nếu bộ nhớ đã được nhận thông qua 'calloc()' hoặc các phương tiện khác như vậy, thì một người có quyền truy cập hợp pháp vào bộ nhớ đó. Mặt khác, tôi tin rằng hầu như mọi hoạt động trên một cấu trúc đều được phép làm bất cứ điều gì nó thích với bất kỳ phần đệm nào trong đó. Mã có thể sử dụng một con trỏ tới cấu trúc để sao chép tất cả các byte trong đó nếu nó không truy cập cấu trúc trong khi chờ đợi, nhưng bảo đảm duy nhất hệ thống sẽ thực hiện liên quan đến byte đệm sẽ là giá trị của chúng trong cấu trúc nguồn sẽ không gây ra vấn đề ở đích. – supercat

2

Câu hỏi của tôi là, là những bit đệm đảm bảo theo tiêu chuẩn là không khởi tạo bởi tuyên bố:

số

Giá trị của đệm được chỉ định:

(C99, 6.2.6.1p6) "Khi một giá trị được lưu trữ trong một đối tượng của cấu trúc hoặc kiểu công đoàn, bao gồm trong một đối tượng thành viên, các byte của biểu diễn đối tượng tương ứng với bất kỳ byte đệm nào có giá trị không xác định"

EDIT: Xem Jens Gustedt answer, C11 hiện nay đảm bảo đệm được thiết lập để 0 trong (hiếm) một số trường hợp

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