2012-02-05 36 views
17

Để thực hiện gói f0f1 vào cùng một byte, chương trình bên dưới có được xác định không?Các trường bit và các số thứ tự

struct S0 { 
     unsigned f0:4; 
     signed f1:4; 
} l_62; 

int main (void) { 
     (l_62.f0 = 0) + (l_62.f1 = 0); 
     return 0; 
} 

Tôi quan tâm đến câu trả lời cho C99 và C11 nếu có lý do để nghĩ rằng nó khác ở đó.

Trong C99, tất cả tôi tìm thấy là 6,5: 2:

Giữa điểm chuỗi trước và bên cạnh một đối tượng có trách nhiệm giá trị được lưu trữ Modi fi ed của nó tối đa một lần bởi việc đánh giá một biểu thức. [...]

Tôi không rõ hậu quả của đoạn này trong chương trình ở trên.

Dựa trên một số lượng lớn các thử nghiệm ngẫu nhiên, hầu hết các trình biên dịch xuất hiện để tạo mã nơi hai bài tập không can thiệp.

+1

Những phần đó của tiêu chuẩn cho tôi đau đầu. Đọc hiện tại của tôi là ý định là UB (ví dụ rõ ràng trong C11 rằng sửa đổi hai lĩnh vực trong hai chủ đề là một khóa học không đồng bộ), nhưng ngôn ngữ trong 6,5 quên đề cập đến bit-lĩnh vực như trong khác nơi các trường bit có xử lý đặc biệt. – AProgrammer

+0

@AProgrammer: Đoạn mã trên có ý nghĩa lôgic rõ ràng (xử lý ghi như thể xảy ra tuần tự, theo thứ tự) và không có lý do tại sao trình biên dịch có tác giả không bị lạm dụng sẽ không tạo mã tạo ra hành vi đó trong trường hợp đơn luồng. Bạn có thể đề xuất bất kỳ lý do chính đáng nào tại sao các tác giả của Tiêu chuẩn có thể dự định trở thành UB không? – supercat

Trả lời

3

C11 xem các ô liền kề có tên bit là một phần của cùng một vị trí bộ nhớ. Các trường bit như vậy không được bảo đảm được cập nhật một cách nguyên tử, nói cách khác nếu một bản cập nhật không được sắp xếp một cách rõ ràng trước khi hành vi khác không được xác định. 3.14 memory location sau đó cũng có một giải thích chi tiết về khi hai trường có thể được coi là ở các vị trí bộ nhớ khác nhau, do đó các bản cập nhật cho chúng có thể được xem xét độc lập.

Nếu bạn muốn thay đổi cấu trúc của bạn

struct S0 { 
     unsigned f0:4; 
     int :0; 
     signed f1:4; 
} l_62; 

như vậy mà có này kỳ quái "vị trí bộ nhớ tách" giữa các lĩnh vực hai bit, mã của bạn sẽ được đảm bảo để được tốt.

Đối với trường hợp C99 có vẻ phức tạp hơn, không có khái niệm chi tiết về vị trí bộ nhớ. Trong một cuộc thảo luận gần đây về danh sách gửi thư hạt nhân Linux, có một tuyên bố nói chung cho tất cả các cặp của các trường bit sẽ có một sự đảm bảo về nguyên tử khi cập nhật bất kỳ một trong số chúng. Điểm bắt đầu của cuộc thảo luận đó là trường hợp gcc bị ô nhiễm một trường không bit bên cạnh một trường bit một cách bất ngờ dẫn tới các sự cố giả mạo.

+2

Sửa đổi cùng một vị trí bộ nhớ là một cuộc đua dữ liệu trong C11, điều đó chắc chắn. Nhưng trong khi 5.1.2.4/4 nói về vị trí bộ nhớ, 6.5/2 chỉ nói về các đối tượng vô hướng. Và tôi không chắc nó là một sự giám sát. Các từ tương ứng trong C++ tương tự nhau, dữ liệu đua nhưng dường như không phải UB cho một biểu thức duy nhất trong một chủ đề duy nhất. – AProgrammer

+0

@AProgrammer: Sẽ không thực tế lắm trên hầu hết các nền tảng để ủy nhiệm đồng thời (các luồng khác nhau) ghi vào các bitfield khác nhau trong cùng một phần tử lưu trữ hoạt động theo kiểu tuần tự nhất quán. Hầu hết các nền tảng có thể, về cơ bản không có chi phí, đảm bảo rằng viết của một trường sẽ không ảnh hưởng đến việc đọc đồng thời của một trường khác, nhưng vì điều đó sẽ không được miễn phí trên tất cả các nền tảng mà Standard không ủy thác nó. Tôi thấy không có gì để cho rằng trình biên dịch không nên được dự kiến ​​sẽ xử lý các trường hợp đơn luồng, tuy nhiên. – supercat

0

Bài tập ở đây là cho các thành viên cấu trúc. Thực tế là chúng xảy ra để chia sẻ cùng một lưu trữ nên không có ảnh hưởng đến logic. Bạn đã không, trên thực tế, thực sự đã thực hiện một nhiệm vụ cho cùng một điều.

Tất nhiên, tôi không phải là luật sư ngôn ngữ.

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