Giả sử unsigned int
không có biểu diễn bẫy, làm một hoặc cả hai câu lệnh được đánh dấu (A) và (B) bên dưới kích hoạt hành vi không xác định, tại sao hoặc tại sao không , và (đặc biệt nếu bạn nghĩ rằng một trong số chúng được xác định rõ ràng nhưng khác không phải là), bạn có cho rằng một khiếm khuyết trong tiêu chuẩn? Tôi chủ yếu quan tâm đến phiên bản hiện tại của tiêu chuẩn C (nghĩa là C2011), nhưng nếu điều này khác với các phiên bản cũ của tiêu chuẩn, hoặc trong C++, tôi cũng muốn biết về điều đó.Hành vi không xác định đối tượng đọc sử dụng loại không phải ký tự khi được viết lần cuối bằng cách sử dụng loại ký tự
(_Alignas
được sử dụng trong chương trình này để loại bỏ bất kỳ câu hỏi của UB do sự liên kết không phù hợp. Các quy tắc tôi thảo luận trong việc giải thích của tôi, tuy nhiên, nói gì về sự liên kết.)
#include <stdlib.h>
#include <string.h>
int main(void)
{
unsigned int v1, v2;
unsigned char _Alignas(unsigned int) b1[sizeof(unsigned int)];
unsigned char *b2 = malloc(sizeof(unsigned int));
if (!b2) return 1;
memset(b1, 0x55, sizeof(unsigned int));
memset(b2, 0x55, sizeof(unsigned int));
v1 = *(unsigned int *)b1; /* (A) */
v2 = *(unsigned int *)b2; /* (B) */
return !(v1 == v2);
}
giải thích của tôi về C2011 là rằng (A) khiêu khích hành vi undefined nhưng (B) được xác định rõ (để lưu trữ một giá trị không xác định vào v2
), bởi vì:
memset
được định nghĩa (§7.24.6.1) để viết thư cho đối số đầu tiên của nó như là -tôi f thông qua một lvalue với loại ký tự, được cho phép cho cả haib1
vàb2
cho mỗi trường hợp đặc biệt ở dưới cùng của §6.5p7.Đối tượng
b1
có loại được khai báo,unsigned char[n]
. Do đó, loại truy cập hiệu quả của nó cũng làunsigned char[n]
mỗi 6,5p6. Bản tuyên bố (A) đọcb1
thông qua một biểu thức lvalue có loại làunsigned int
, đó không phải là loại hiệu quả củab1
cũng không phải bất kỳ ngoại lệ nào khác trong 6,5p7, do đó hành vi không xác định.Đối tượng được trỏ đến bởi
b2
không có loại được khai báo. Giá trị được lưu trữ trong nó (bởimemset
) là (as-if) thông qua một lvalue với loại ký tự, vì vậy trường hợp thứ hai của 6,5p6 không áp dụng. Giá trị không phải là được sao chép từ mọi nơi, vì vậy trường hợp thứ ba 6,5p6 cũng không áp dụng. Do đó, loại hiệu quả của đối tượng là loại giá trị được sử dụng cho truy cập, làunsigned int
và các quy tắc của 6.5p7 đều hài lòng.Cuối cùng, mỗi 6.2.6.1, giả sử
unsigned int
không có cơ quan đại diện bẫy, hoạt độngmemset
đã tạo ra các đại diện của một sốunsigned int
giá trị không xác định trong mỗib1
vàb2
. Do đó, nếu không (A) cũng như (B) gây ra hành vi không xác định, thì các giá trị thực tế trongv1
vàv2
không xác định nhưng chúng bằng nhau.
Bình luận:
Các không đối xứng của các quy tắc "loại dựa trên răng cưa" (có nghĩa là, 6.5p7), cho phép một đối tượng với bất kỳ loại hiệu quả để được truy cập bởi một giá trị trái với kiểu nhân vật, nhưng không phải ngược lại, là một nguồn gây nhầm lẫn liên tục. Trường hợp thứ hai của 6.5p6 dường như đã được thêm vào đặc biệt để ngăn chặn hành vi không xác định của nó để đọc một giá trị được khởi tạo bởi memset
(hoặc, cho rằng vấn đề, calloc
) nhưng, bởi vì nó chỉ áp dụng cho các đối tượng không có loại khai báo, nguồn gây nhầm lẫn bổ sung.
'A' rõ ràng là vi phạm bí danh; nhưng tiêu chuẩn dường như không nói rõ những gì hiệu ứng 'memset' có hiệu lực loại –
Tôi đã bắt đầu [một câu hỏi khác] (http://stackoverflow.com/questions/30970251/what-is-the-effective-type- of-an-object-by-memset) đặc biệt để bao gồm loại dữ liệu có hiệu quả được ghi bởi 'memset' –