2012-04-26 36 views
6

Tôi nhận được hành vi bất thường với mã của tôi, đó là như sauHành vi của nhà điều hành sizeof trong C

#include<stdio.h> 
struct a 
{ 
    int x; 
    char y; 
}; 
int main() 
{ 
    struct a str; 
    str.x=2; 
    str.y='s'; 
    printf("%d %d %d",sizeof(int),sizeof(char),sizeof(str)); 
    getch(); 
    return 0; 
} 

Đối với đoạn mã này tôi nhận được kết quả:

4 1 8 

Tính đến tôi kiến thức cấu trúc có chứa một biến số nguyên của kích thước 4 và một biến char kích thước 1 do đó kích thước của cấu trúc nên là 5. Nhưng làm thế nào đến kích thước của cấu trúc là 8. Tôi đang sử dụng trình biên dịch C++ trực quan. Tại sao hành vi này?

+2

Trong các đối số 'printf()', bạn thực sự nên bỏ các giá trị 'sizeof' thành' (int) '... hoặc' (unsigned long) 'và sử dụng' "% lu" '... hoặc, nếu bạn có C99, sử dụng '"% zu "'. – pmg

+2

@pmg: Chính xác. Bởi vì 'sizeof()' trả về một giá trị kiểu 'size_t'. –

Trả lời

12

Nó được gọi là Structure Padding

Có cấu trúc dữ liệu mà bắt đầu vào ngày 4 alignment byte từ (trên CPU với 4 xe buýt byte và bộ vi xử lý) là hiệu quả hơn khi di chuyển dữ liệu xung quanh bộ nhớ, và giữa RAM và CPU.

Bạn thường có thể tắt tính năng này bằng các tùy chọn trình biên dịch và/hoặc pragmas, các chi tiết cụ thể của việc này sẽ tùy thuộc vào trình biên dịch cụ thể của bạn.

Hy vọng điều này sẽ hữu ích.

+1

_Bạn thường có thể chuyển đổi này off_, nhưng tôi khuyên bạn không bao giờ làm như vậy, ngay cả khi bạn cần phân tích cú pháp một số gói nhị phân và có ý tưởng tạo cấu trúc tương tự để mã hóa/giải mã dễ dàng. Hãy nhớ rằng, trên một số mục tiêu (có thể trong quá khứ chỉ) đọc không có dấu có thể dẫn đến sự cố bộ vi xử lý! Ngoài ra điều này làm cho mã của bạn hoàn toàn không thể chuyển đổi. – Yury

+0

@Yury: nếu trình biên dịch cho phép '#pragma pack' hoặc nội dung tương tự trên nền tảng như vậy, bình thường nó sẽ tạo mã để giải quyết vấn đề đọc được liên kết (thường là' memcpy' thành vị trí được căn chỉnh riêng biệt), nếu không cấu trúc như vậy sẽ không sử dụng được . –

8

Trình biên dịch chèn phần đệm cho mục đích tối ưu hóa và các mục đích. Ở đây, trình biên dịch chèn 3 byte giả giữa (hoặc sau) cả hai thành viên của bạn.

Bạn có thể xử lý căn chỉnh với chỉ thị #pragma.

+1

có lẽ (1) 3 byte và (2) sau – Vlad

+0

Có, đó là 3 byte trong trường hợp này, nhưng tôi nghĩ nó nằm giữa, phải không? – md5

+0

tốt, nó phụ thuộc vào độ cuối của máy mục tiêu :) hoặc iiiidddc hoặc iiiicddd. – Vlad

0

Chủ yếu để minh họa cách đệm thực sự hoạt động, tôi đã sửa đổi chương trình của bạn một chút.

#include<stdio.h> 
struct a 
{ 
    int x; 
    char y; 
    int z; 
}; 
int main() 
{ 
    struct a str; 
    str.x=2; 
    str.y='s'; 
    str.z = 13; 

    printf ("sizeof(int) = %lu\n", sizeof(int)); 
    printf ("sizeof(char) = %lu\n", sizeof(char)); 
    printf ("sizeof(str) = %lu\n", sizeof(str)); 

    printf ("address of str.x = %p\n", &str.x); 
    printf ("address of str.y = %p\n", &str.y); 
    printf ("address of str.z = %p\n", &str.z); 

    return 0; 
} 

Lưu ý rằng tôi đã thêm phần tử thứ ba vào cấu trúc. Khi tôi chạy chương trình này, tôi nhận được:

[email protected]:~/so$ ./padding 
sizeof(int) = 4 
sizeof(char) = 1 
sizeof(str) = 12 
address of str.x = 0x7fffc962e070 
address of str.y = 0x7fffc962e074 
address of str.z = 0x7fffc962e078 
[email protected]:~/so$ 

Phần này minh họa phần đệm được tô sáng bên dưới.

address of str.y = 0x7fffc962e074 
address of str.z = 0x7fffc962e078 

Trong khi y chỉ là một ký tự, hãy lưu ý rằng z là 4 byte đầy đủ.