2012-06-22 29 views
8

Tôi đã nhìn thấy vô số câu hỏi của biểu mẫu "Tôi không thích đệm làm thế nào để tắt nó đi", nhưng chưa tìm thấy bất cứ điều gì về buộc trình biên dịch để cung cấp thêm đệm .C (++) struct buộc đệm thêm

Các trường hợp cụ thể mà tôi có vẻ như

struct particle{ 
    vect2 s; 
    vect2 v; 
    int rX; 
    int rY; 
    double mass; 
    int boxNum; 
}; 

đâu vect2 là một đơn giản struct {double x; double y;} vect2. Để sử dụng SSE2, tôi cần để có thể tải một cặp đôi, liên kết với 16 byte ranh giới. Điều này được sử dụng để làm việc, cho đến khi tôi thêm int, đẩy kích thước cấu trúc của tôi từ 48 byte lên 56 byte. Kết quả là segfaults.

Có một số loại chỉ thị trình biên dịch tôi có thể sử dụng hoặc nói "pad cấu trúc này để biến nó thành bội số 16 byte" hay "cấu trúc này có căn chỉnh 16 byte"? Tôi biết tôi có thể làm điều đó bằng tay (tacking trên một char thêm [12], ví dụ), nhưng tôi thực sự chỉ cần nói với trình biên dịch (GCC, tốt nhất là ICC tương thích), và không phải làm điều đó bằng tay nếu tôi thay đổi struct trong tương lai.

+7

Trong C++ 11 hiện có ['alignas'] (http://en.cppreference.com/w/cpp/language/alignas) cho mục đích này. – ildjarn

+0

Tôi không nghĩ rằng GCC đã thực hiện điều này được nêu ra, mặc dù. – chris

+2

Sau đó, xem http://stackoverflow.com/questions/6959261/how-can-i-simulate-alignast –

Trả lời

3

Tôi đang thêm câu trả lời của riêng mình cho điều này, trong trường hợp ai đó tìm kiếm giải pháp.Giải pháp của Mark là một giải pháp gọn gàng, và đáp ứng yêu cầu tự động, nhưng nó không phải là khi tôi kết thúc. Tôi muốn tránh điều này, đó là lý do tôi hỏi những câu hỏi, nhưng có một "tầm thường" giải pháp:

struct particle{ 
    vect2 s; 
    vect2 v; 
    int rX; 
    int rY; 
    double mass; 
    int boxNum; 
    char padding[12]; 
}; 

Bằng tay kiểm tra kích thước hiện tại của struct, bạn có thể thêm một số lượng thích hợp chars, (hoặc bất cứ điều gì khác, nhưng char cho phép bạn làm điều đó theo byte), để làm cho nó đúng kích cỡ. Điều này cho thấy hiệu suất tốt nhất, cũng như sự đơn giản, mặc dù nó yêu cầu cập nhật mỗi khi cấu trúc thay đổi. Trong trường hợp này là tốt, mặc dù nếu bạn có một cấu trúc có thể thay đổi kích thước tùy thuộc vào các tùy chọn, đó sẽ là vấn đề.

Lưu ý rằng struct của tôi là 56 byte và tôi đã thêm 12 để tạo thành 64 byte. Toán học đó không hoạt động, vì đoạn đường sau int đã được thêm 4 byte vào ranh giới 8 byte; struct thực sự chỉ có 52 byte trước đây. Chỉ có thêm 5 char s có thể đã hoạt động, bằng cách làm dài struct 57 byte, đã được chuyển thành 64, nhưng đó không phải là giải pháp tốt, đó là lý do tại sao tôi sử dụng 12 để làm cho nó hoạt động chính xác.

+6

Điều đó có vẻ hợp lý với các yêu cầu về hiệu năng; vì lợi ích của đồng nghiệp và người bảo trì tương lai (bao gồm cả bản thân tương lai của bạn) * xin vui lòng * bình luận sửa lỗi và thêm thời gian biên dịch khẳng định rằng 'struct' là bội số của kích thước 16 byte. – ecatmur

+0

Cảm ơn, đó là một điểm rất tốt. – zebediah49

+1

Có lý do cụ thể nào khiến bạn không muốn để điều này cho trình biên dịch hay không, ví dụ: với '__attribute __ ((liên kết (16)))'? – Pedro

1

Thông số C++ 11 mới cũng có new feature cho điều này, mặc dù tôi không tin rằng nhiều nhà cung cấp đã triển khai chúng.

Bạn có thể thử gói pragma, mặc dù nó không được hỗ trợ bởi thông số kỹ thuật. Cả GCC và MS đều hỗ trợ nó.

Điều này căn chỉnh cấu trúc trên ranh giới 1 byte, mặc dù bạn có thể thay đổi số thành bất kỳ thứ gì bạn muốn.

#pragma pack(push,1) 
// ... 
#pragma pack(pop) 

update:

Vì vậy, dường như trên sẽ không làm việc vì nó chỉ co lại đệm, không bao giờ mở rộng nó. Rất tiếc, tôi không có một môi trường thử nghiệm chiều nay.

Có thể sử dụng liên minh ẩn danh sẽ hoạt động. Tôi biết nó sẽ mở rộng đến kích thước lớn nhất, mặc dù tôi không biết nếu bạn nhận được bất kỳ đảm bảo về sự liên kết khác.

template<typename T, size_t padding_size> 
    struct padded_field { 
    union { 
     T value; 
     uint8_t padding[padding_size]; 
    }; 
    }; 
+3

Tôi đã thử điều đó; khi đặt thành 4, nó giảm xuống còn 52 byte .. nhưng khi đặt thành 16, nó vẫn ở mức 56, vì vậy tôi giả định rằng nó không mở rộng phần đệm, chỉ đóng gói chặt chẽ hơn. – zebediah49

+1

Tôi không quen với việc triển khai của gcc, nhưng mỗi [tài liệu Visual C++] (http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx), "Căn chỉnh của một thành viên sẽ nằm trên một ranh giới hoặc là bội số của n hoặc bội số của kích thước của thành viên, ** tùy theo số nào nhỏ hơn **. " –

1

Không thử nghiệm, nhưng điều này có thể làm việc:

#include <xmmintrin.h> 

struct particle{ 
    union { 
    vect2 s; 
    __m128 s_for_alignment; 
    }; 
    union { 
    vect2 v; 
    __m128 v_for_alignment; 
    }; 
    ... 
}; 

Tôi biết rằng gcc có vấn đề sắp xếp __m128 một cách chính xác trước đây, nhưng những người cần được cố định bởi bây giờ.

+0

Trong trường hợp đó tôi cũng có thể đi với 'union vect2 {__m128d s; struct {double x; double y;};}; ', nhưng có, đó có thể là cách để đi. – zebediah49

+0

Kiểm tra cho biết rằng công việc này chậm hơn khoảng 10% so với cách thủ công; Tôi không hoàn toàn chắc chắn tại sao. – zebediah49

+0

Điên. Bất kỳ sự khác biệt trong asm tạo ra? – ecatmur

8

Bạn có thể lồng hai cấu trúc để tự động dán cấu trúc mà không cần phải tự theo dõi kích thước.

struct particle 
{ 
    // ... 
}; 

{ 
    particle p; 
    char padding[16-(sizeof(particle)%16)]; 
}; 

Phiên bản này không may thêm 16 byte nếu cấu trúc đã là bội số của 16. Không thể tránh khỏi vì tiêu chuẩn không cho phép mảng có độ dài bằng 0.

Một số trình biên dịch làm phép zero mảng chiều dài như một phần mở rộng, và trong trường hợp đó bạn có thể làm điều này thay vì:

struct particle_wrapper 
{ 
    particle p; 
    char padding[sizeof(particle)%16 ? 16-(sizeof(particle)%16) : 0]; 
}; 

Phiên bản này không thêm bất kỳ byte đệm nếu cấu trúc đó đã là một bội số của 16

+1

Bạn có thể tránh thêm 16 byte bằng cách thực hiện 'char padding [(sizeof (particle) + 15) & ~ 15]'. – Pedro

+0

@Pedro, tôi nghĩ điều đó không đúng. –

+1

Đó là, nhưng chỉ hoạt động bởi vì 16 là một sức mạnh của 2. Nó dễ dàng hơn để hiểu nếu bạn xem xét rằng '~ 15' là' 1..10000' trong nhị phân, tức là nó lọc ra bốn bit cuối cùng, để lại một bội số của 16. Vì điều này chỉ cắt bớt số thành bội số của 16, chúng ta phải thêm 15 đầu tiên để chúng ta có được bội số cao nhất tiếp theo. – Pedro

3

Trong gcc, bạn có thể căn chỉnh các loại và biến tùy ý bằng __attribute__((aligned(...))). Ví dụ của bạn, điều này sẽ là

struct particle{ 
    vect2 s; 
    vect2 v; 
    int rX; 
    int rY; 
    double mass; 
    int boxNum; 
} __attribute__((aligned (16))); 

Điều này tự động tạo cấu trúc để mảng được căn chỉnh chính xác.