2010-09-16 37 views
6

Tôi không hiểu tại saoKích thước của một cấu trúc có hai con trỏ void là 4?

struct e{ 
    void * a; 
    void * b[]; 
} 

có sizeof (e) == 4 trong khi

struct f{ 
    void * a; 
    void * b; 
} 

có sizeof (f) == 8.

+0

A [thảo luận về tính hợp pháp của "struct hack" trong ansi c] (http://stackoverflow.com/questions/3711233/). Tìm kiếm trên "struct hack" trên So không trả lại nhiều sự quan tâm ngay bây giờ, nhưng đó là cụm từ bạn đang tìm kiếm. – dmckee

Trả lời

12

Cấu trúc thứ hai trong cấu trúc đầu tiên không phải là con trỏ, mà là thành viên mảng linh hoạt FAM. Nó được sử dụng khi bạn có bộ đệm dài và đặt e khi bắt đầu bộ đệm đó. Sau đó, bạn có thể lập chỉ mục bộ nhớ còn lại theo đối tượng e bằng cách sử dụng FAM đó và xử lý bộ nhớ đó dưới dạng mảng void*.

Tiêu chuẩn nói (nhấn mạnh của tôi)

Là một trường hợp đặc biệt, yếu tố cuối cùng của một cấu trúc với nhiều hơn một thành viên có tên có thể có một loại mảng không đầy đủ; đây được gọi là thành viên mảng linh hoạt. Trong hầu hết các trường hợp, thành viên mảng có thể đọc được sẽ bị bỏ qua. Cụ thể, kích thước của cấu trúc giống như thành viên mảng linh hoạt bị bỏ qua ngoại trừ việc nó có thể có nhiều dấu rãnh chéo hơn sự thiếu sót sẽ hàm ý.

Ví dụ, kết quả đầu ra mã sau 1 cho struct mà không có, nhưng 4 cho struct với FAM trên GCC, bởi vì để nguyên truy cập cần FAM để được sắp xếp đúng cách (trên một ranh giới 4 byte trong này ví dụ)

struct A { 
    char a; 
}; 

struct B { 
    char a; 
    int flex[]; 
}; 

int main() { 
    printf("sizeof A: %d\nsizeof B: %d\n", 
     (int)sizeof(struct A), 
     (int)sizeof(struct B) 
    ); 

    struct B *b = malloc(sizeof *b + sizeof(int[3])); 
    b->a = 'X'; 
    b->flex[0] = 1; 
    b->flex[1] = 2; 
    b->flex[2] = 3; 
    free(b); 
} 
+0

Vì bạn đã biên soạn nội dung trong các bài đăng khác nhau và thêm ví dụ, tôi đã chấp nhận câu trả lời của bạn so với bài trước. –

17
struct e{ 
    void * a; 
    void * b[]; 
//   ^^ 
} 

Các [] trong một cấu trúc làm cho b thành viên mảng linh hoạt C99 ". Như vậy sizeof(e) sẽ được tính kích thước của chỉ a, đó là 4.

Từ C99 § 6.7.2.1/16:

Là một trường hợp đặc biệt, yếu tố cuối cùng của một cấu trúc với nhiều hơn một thành viên có tên có thể có loại mảng không hoàn chỉnh; đây được gọi là thành viên mảng linh hoạt linh hoạt. Trong hầu hết các trường hợp, thành viên mảng linh hoạt bị bỏ qua. Cụ thể, kích thước của cấu trúc như thể thành viên mảng linh hoạt bị bỏ qua, ngoại trừ việc nó có thể có nhiều phần đệm phía sau hơn là thiếu sót sẽ hàm ý.

Tuy nhiên, khi toán tử . (hoặc ->) có toán hạng bên trái là (một con trỏ đến) cấu trúc với thành viên mảng linh hoạt và tên toán hạng phù hợp với thành viên đó, nó hoạt động như thể thành viên đó đã được thay thế bằng mảng dài nhất (với cùng loại phần tử) sẽ không làm cho cấu trúc lớn hơn đối tượng được truy cập; độ lệch của mảng phải giữ nguyên giá trị của thành viên mảng linh hoạt, ngay cả khi giá trị này khác với giá trị của mảng thay thế. Nếu mảng này không có phần tử, nó hoạt động như thể nó có một phần tử nhưng hành vi không được xác định nếu có bất kỳ nỗ lực nào được thực hiện để truy cập phần tử đó hoặc tạo ra một con trỏ qua nó.

+1

Điều đó có nghĩa là tôi không thể truy cập vào nó? –

+0

@Alan: Không, bạn vẫn có thể truy cập 'b'. – kennytm

+0

@Alan: no; nó chỉ có nghĩa là sizeof() trả về kết quả bạn quan sát. –

2

Điều này là do cấu trúc thứ hai sử dụng mảng thành viên linh hoạt linh hoạt.Giải thích về kết quả sizeof là trong Wikipedia.

1

void * b[]; không hợp lệ trong C89, vì vậy điều đó có nghĩa là bạn đang sử dụng trình biên dịch C99.

C99 giới thiệu một phương tiện để xác định "struct hack": nó bây giờ gọi là "thành viên mảng linh hoạt" và bộ nhớ trước khi nó được phân bổ, kích thước của nó là 0.

+0

Điều này cũng quan trọng cần lưu ý vì tôi đã cố gắng gắn bó với C89. Cảm ơn! –

0

Bởi vì là người đầu tiên không tuyên bố bất kỳ không gian cho các con trỏ trong "b".

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