2012-07-08 45 views
33

Sự khác nhau giữa sizeof và alignof là gì?Sự khác nhau giữa sizeof và alignof là gì?

#include <iostream> 

#define SIZEOF_ALIGNOF(T) std::cout<< sizeof(T) << '/' << alignof(T) << std::endl 

int main(int, char**) 
{ 
     SIZEOF_ALIGNOF(unsigned char); 
     SIZEOF_ALIGNOF(char); 
     SIZEOF_ALIGNOF(unsigned short int); 
     SIZEOF_ALIGNOF(short int); 
     SIZEOF_ALIGNOF(unsigned int); 
     SIZEOF_ALIGNOF(int); 
     SIZEOF_ALIGNOF(float); 
     SIZEOF_ALIGNOF(unsigned long int); 
     SIZEOF_ALIGNOF(long int); 
     SIZEOF_ALIGNOF(unsigned long long int); 
     SIZEOF_ALIGNOF(long long int); 
     SIZEOF_ALIGNOF(double); 
} 

chí đầu ra

1/1 1/1 2/2 2/2 4/4 4/4 4/4 4/4 4/4 8/8 8/8 8/8

Tôi nghĩ mình không hiểu căn chỉnh là gì ...?

+16

thử lại bằng các cấu trúc thay vì các kiểu gốc. –

+1

'Trả về căn chỉnh theo byte (lũy thừa số nguyên là hai) cho bất kỳ thể hiện nào của kiểu đã cho' - http://en.cppreference.com/w/cpp/language/alignof. 'sizeof' chỉ cho kích thước, tính bằng byte, tất nhiên. – chris

+1

Có thể đáng nhắc đến - [sizeof luôn là bội số của alignof] (http://stackoverflow.com/questions/4637774/is-the-size-of-a-struct-required-to-be-an-exact-multiple -of-the-alignment-of-tha) – Steve314

Trả lời

3

sizeof operator cung cấp cho bạn kích thước tính theo byte của loại thực hoặc thể hiện của một loại.

alignof operator cung cấp cho bạn căn chỉnh theo byte bắt buộc cho bất kỳ phiên bản nào của loại đã cho.

+6

"căn chỉnh" là gì? – user1494506

14

Hai toán tử thực hiện những điều cơ bản khác nhau. sizeof cho kích thước của một loại (chiếm bao nhiêu bộ nhớ) trong khi alignof cho biết cần phải căn chỉnh bao nhiêu byte. Nó chỉ như vậy sẽ xảy ra rằng các nguyên thủy bạn đã thử nghiệm có một yêu cầu liên kết giống như kích thước của chúng (có ý nghĩa nếu bạn nghĩ về nó).

Hãy suy nghĩ về những gì sẽ xảy ra nếu bạn có một cấu trúc thay vì:

struct Foo { 
    int a; 
    float b; 
    char c; 
}; 

alignof(Foo) sẽ trở lại 4.

+1

tại sao? 'alignof' là gì? – user1494506

+1

@tskuzzy bạn nói 'alignof (Foo)' sẽ trả về 4. Nhưng nó phụ thuộc vào ABI mục tiêu. Vì vậy, điều này có thể đúng trên ia32 (x86) nhưng không phải trên ARM, MIPS, PowerPC, v.v. – ydroneaud

+3

4 ??? Tôi thực sự không hiểu – Offirmo

54

Vâng, "bộ nhớ" về cơ bản là một mảng rất lớn của các byte. Tuy nhiên, hầu hết những thứ lớn hơn như số nguyên cần nhiều hơn 1 byte để lưu trữ chúng - ví dụ, giá trị 32 bit sẽ sử dụng 4 byte bộ nhớ liên tiếp.

Hiện tại, các mô-đun bộ nhớ trong máy tính của bạn thường không phải là "byte"; chúng cũng được tổ chức với một vài byte "song song", giống như các khối 4 byte.

Đối với một CPU, nó dễ dàng hơn nhiều = hiệu quả hơn = hiệu suất tốt hơn để không "chéo" như khối biên giới khi đọc một cái gì đó giống như một số nguyên:

memory byte 0 1 2 3  4 5 6 7  8 9 10 11 
integer  goooood 
        baaaaaaaaad 

Đây là những gì "liên kết" nói: một căn chỉnh 4 có nghĩa là dữ liệu thuộc loại này nên (hoặc phải, tùy thuộc vào CPU) được lưu trữ bắt đầu từ một địa chỉ là bội số của 4.

Bạn quan sát rằng sizeof == alignof là không chính xác; thử cấu trúc. Các cấu trúc cũng sẽ được căn chỉnh (vì các thành viên riêng lẻ của chúng cần kết thúc trên các địa chỉ chính xác), nhưng kích thước của chúng sẽ lớn hơn nhiều.

+14

Điểm bổ sung - mặc dù x86 sẽ thực hiện đọc và ghi (từ từ nhưng chính xác) cho hầu hết mọi thứ, một số kiến ​​trúc yêu cầu tất cả các hoạt động phải được căn chỉnh và thậm chí trong x86 có một số trường hợp đặc biệt phải được căn chỉnh (SIMD) hướng dẫn, tôi nghĩ). – Steve314

+0

cảm ơn! bây giờ tôi nhận được nó – user1494506

+2

@ user1494506 - Nếu câu trả lời này hoặc bất kỳ câu trả lời nào khác trả lời chính xác câu hỏi của bạn, * xem xét * đánh dấu nó đúng. (Tất nhiên đây là * hoàn toàn là lựa chọn của bạn * Đừng ép buộc chấp nhận câu trả lời bởi vì mọi người nói như vậy) (ví dụ như tôi đang nói bây giờ)) :) – ArjunShankar

5

Giá trị alignof giống với giá trị của sizeof cho các loại cơ bản.

Sự khác biệt nằm trong các loại dữ liệu được xác định đã sử dụng, chẳng hạn như sử dụng cấu trúc; ví dụ:

typedef struct { int a; double b; } S; 
//cout<<alignof(s);        outputp: 8; 
//cout<<sizeof(S);        output: 12; 

do đó giá trị sizeof là tổng kích thước cần thiết cho loại dữ liệu nhất định; và giá trị alignof là yêu cầu căn chỉnh của phần tử lớn nhất trong cấu trúc.

Sử dụng alignof: cấp phát bộ nhớ trên một ranh giới căn chỉnh cụ thể.

6

Câu hỏi cũ (mặc dù không được đánh dấu là đã trả lời ..) nhưng nghĩ ví dụ này làm cho sự khác biệt rõ ràng hơn một chút ngoài câu trả lời của Christian Stieber. Ngoài ra câu trả lời Meluha chứa một lỗi như sizeof (S) đầu ra là 16 không 12.

// c has to occupy 8 bytes so that d (whose size is 8) starts on a 8 bytes boundary 
//   | 8 bytes | | 8 bytes | | 8 bytes | 
struct Bad { char c;  double d;  int i;  }; 
cout << alignof(Bad) << " " << sizeof(Bad) << endl; // 8 24 

//    | 8 bytes | | 8 bytes |  
struct Good { double d;  int i; char c;   }; 
cout << alignof(Good) << " " << sizeof(Good) << endl; // 8 16 

Nó cũng chứng minh rằng nó là thành viên đặt hàng tốt nhất bằng kích thước với lớn đầu tiên (đôi trong trường hợp này), như những người khác thành viên là bị ràng buộc bởi thành viên đó.

2

Đối với các câu trả lời được cung cấp, có vẻ như có một số nhầm lẫn về những gì căn chỉnh thực sự là. Sự nhầm lẫn có thể phát sinh bởi vì có 2 loại căn chỉnh.

1. alignment Member

Đây là một biện pháp định tính mà giải thích rõ ràng như thế nào lớn một thể hiện là trong số byte cho một trật tự cụ thể của các thành viên trong kiểu cấu trúc/lớp. Nói chung, các trình biên dịch có thể cấu trúc nhỏ gọn/các thể hiện lớp nếu các thành viên được sắp xếp theo kích thước byte của chúng theo thứ tự giảm dần (tức là lớn nhất đầu tiên, các thành viên nhỏ nhất cuối cùng) trong cấu trúc. Hãy xem xét:

struct A 
{ 
    char c; float f; short s; 
}; 

struct B 
{ 
    float f; short s; char c; 
}; 

Cả hai cấu trúc đều chứa chính xác cùng một thông tin. Vì lợi ích của ví dụ này; loại float mất 4 byte, loại ngắn mất 2 và ký tự mất 1 byte. Tuy nhiên, cấu trúc đầu tiên A có các thành viên theo thứ tự ngẫu nhiên, trong khi cấu trúc thứ hai B yêu cầu các thành viên theo kích thước byte của chúng (điều này có thể khác với kiến ​​trúc nhất định, tôi giả sử kiến ​​trúc CPU intel x86 với sự liên kết 4 byte trong ví dụ này). Bây giờ xem xét kích thước của các cấu trúc:

printf("size of A: %d", sizeof (A)); // size of A: 12; 
printf("size of B: %d", sizeof (B)); // size of B: 8; 

Nếu bạn mong chờ kích thước là 7 byte, bạn sẽ được giả định rằng các thành viên là đóng gói vào cấu trúc bằng cách sử dụng một liên kết 1-byte. Trong khi một số trình biên dịch cho phép điều này, nói chung hầu hết các trình biên dịch sử dụng 4-byte hoặc thậm chí 8-byte sắp xếp do lý do lịch sử (hầu hết CPU làm việc với DWORD (double-word) hoặc QWORD (quad-word) mục đích chung đăng ký).

Có 2 cơ chế đệm tại nơi làm việc để đạt được đóng gói.

  1. Thứ nhất, mỗi thành viên có kích thước nhỏ hơn so với byte byte-alignment là 'sáp nhập' với thành viên tiếp theo (s) nếu kết quả kích thước byte là nhỏ hơn hoặc bằng byte-alignment. Trong cấu trúc B, các thành viên s và c có thể được sáp nhập theo cách này; kích thước kết hợp của chúng là 2 byte cho s + 1 byte cho c == 3 byte < = căn chỉnh 4 byte. Đối với cấu trúc A, không có sự hợp nhất như vậy có thể xảy ra, và mỗi thành viên tiêu thụ hiệu quả 4 byte trong bao bì của cấu trúc.

  2. Tổng kích thước của cấu trúc lại được đệm để cấu trúc tiếp theo có thể bắt đầu tại ranh giới căn chỉnh. Trong ví dụ B tổng số byte sẽ là 7. Ranh giới 4 byte tiếp theo nằm ở byte 8, do đó cấu trúc được đệm với 1 byte để cho phép phân bổ mảng như là một chuỗi các trường hợp chặt chẽ.

Lưu ý rằng Visual C++/GCC cho phép sắp xếp khác nhau của 1 byte, 2 và bội số cao hơn 2 byte.Hiểu rằng điều này làm việc với khả năng của trình biên dịch của bạn để tạo ra mã tối ưu cho kiến ​​trúc của bạn. Thật vậy, trong ví dụ sau, mỗi byte sẽ được đọc dưới dạng một byte đơn bằng cách sử dụng lệnh một byte cho mỗi thao tác đọc. Trong thực tế, phần cứng vẫn sẽ lấy toàn bộ dòng bộ nhớ chứa mỗi byte đọc vào bộ đệm, và thực hiện lệnh 4 lần, ngay cả khi 4 byte nằm trong cùng một DWORD và có thể được nạp trong thanh ghi CPU trong 1 lệnh.

#pragma pack(push,1) 
struct Bad 
{ 
    char a,b,c,d; 
}; 
#pragma pack(pop) 

2. alignment Allocation

này liên quan chặt chẽ với các cơ chế đệm thứ 2 được giải thích trong phần trước, tuy nhiên, một llocation sắp xếp có thể được quy định trong các biến thể của malloc/memalloc chức năng phân bổ. Do đó, có thể phân bổ một đối tượng tại một ranh giới liên kết khác nhau (thường cao hơn 2) so với liên kết byte của cấu trúc/kiểu đối tượng gợi ý.

size_t blockAlignment = 4*1024; // 4K page block alignment 
void* block = malloc(sizeof(T) * count, blockAlignment); 

Mã sẽ đặt khối các trường hợp đếm kiểu T trên các địa chỉ kết thúc vào bội số của 4096.

Lý do cho việc sử dụng sự sắp xếp, phân bổ như vậy một lần nữa hoàn toàn kiến ​​trúc. Ví dụ, việc đọc và viết các khối từ các địa chỉ liên kết trang nhanh hơn vì phạm vi địa chỉ vừa với các lớp bộ đệm. Các phạm vi được phân tách trên các trang 'thùng rác' khác nhau trong bộ nhớ cache khi vượt qua ranh giới trang. Các phương tiện khác nhau (các kiến ​​trúc bus) có các mẫu truy cập khác nhau và có thể hưởng lợi từ các sự sắp xếp khác nhau. Nói chung, sự sắp xếp các kích thước trang 4, 16, 32 và 64 K không phải là hiếm.

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