2012-06-21 11 views
6

Tôi muốn kích thước của cấu trúc C là bội số của 16 byte (16B/32B/48B/..). Không quan trọng kích thước của nó là bao nhiêu, nó chỉ cần là bội số của 16B. Làm thế nào tôi có thể thực thi trình biên dịch để làm điều đó? Cảm ơn.C liên kết kích thước cấu trúc

+4

Whats trình biên dịch? – Joe

+1

Tiêu đề của bạn sử dụng căn chỉnh từ nhưng cơ thể của câu hỏi của bạn nói về kích thước của cấu trúc. Điều gì mà bạn thực sự muốn thực hiện? Và tôi cũng tò mò là tại sao. –

+0

Và đây là một bài viết hiện có cung cấp một giải pháp bằng cách sử dụng một công đoàn để pad đến một kích thước cụ thể. Tuy nhiên, giải pháp đó đòi hỏi phải biết kích thước của struct [Size of Struct] (http://stackoverflow.com/questions/8705665/force-specific-struct-size-in-c) tuy nhiên những gì bạn cần làm là sử dụng một phép tính kích thước cho mảng char chẳng hạn như (sizeof (struct it)/16 + 1) * 16 thay vì hằng số. –

Trả lời

5

Kích thước của cấu trúc C sẽ phụ thuộc vào các thành viên của cấu trúc, loại của chúng và số lượng của chúng. Có thực sự là không có cách tiêu chuẩn để buộc trình biên dịch để làm cho cấu trúc là một bội số của một số kích thước. Một số trình biên dịch cung cấp một pragma mà sẽ cho phép bạn thiết lập ranh giới liên kết tuy nhiên đó thực sự là một điều khác. Và có thể có một số sẽ có một bối cảnh như vậy hoặc cung cấp một pragma như vậy.

Tuy nhiên, nếu bạn nhấn mạnh vào phương pháp này sẽ là phân bổ bộ nhớ của cấu trúc và buộc phân bổ bộ nhớ làm tròn tới kích thước 16 byte tiếp theo.

Vì vậy, nếu bạn có cấu trúc như thế này.

struct _simpleStruct { 
    int iValueA; 
    int iValueB; 
}; 

Sau đó, bạn có thể làm điều gì đó như sau.

{ 
    struct _simpleStruct *pStruct = 0; 
    pStruct = malloc ((sizeof(*pStruct)/16 + 1)*16); 
    // use the pStruct for whatever 
    free(pStruct); 
} 

Điều này sẽ làm là đẩy kích thước lên đến kích thước 16 byte tiếp theo cho đến khi bạn quan tâm. Tuy nhiên những gì bộ cấp phát bộ nhớ có thể hoặc không thể cung cấp cho bạn một khối thực sự là kích thước đó. Khối bộ nhớ thực sự có thể lớn hơn yêu cầu của bạn.

Nếu bạn định làm điều gì đó đặc biệt, ví dụ, giả sử bạn sẽ viết cấu trúc này cho một tệp và bạn muốn biết kích thước khối thì bạn sẽ phải thực hiện cùng một phép tính được sử dụng trong malloc() thay vì sử dụng toán tử sizeof() để tính toán kích thước của cấu trúc.

Vì vậy, điều tiếp theo sẽ là viết toán tử sizeof() của riêng bạn bằng cách sử dụng macro chẳng hạn như.

#define SIZEOF16(x) ((sizeof(x)/16 + 1) * 16) 

Theo tôi biết không có phương pháp đáng tin cậy để kéo kích thước của khối được phân bổ từ con trỏ. Thông thường một con trỏ sẽ có một khối cấp phát bộ nhớ được sử dụng bởi các chức năng quản lý bộ nhớ heap sẽ chứa các thông tin quản lý bộ nhớ khác nhau như kích thước khối được phân bổ mà thực sự có thể lớn hơn số lượng bộ nhớ được yêu cầu. Tuy nhiên, định dạng cho khối này và vị trí của nó tương ứng với địa chỉ bộ nhớ thực được cung cấp sẽ phụ thuộc vào thời gian chạy của trình biên dịch C.

+0

Bạn nên [không bỏ giá trị trả về của 'malloc()', trong C] (http://stackoverflow.com/a/605858/28169). – unwind

5

Điều này phụ thuộc hoàn toàn vào trình biên dịch và các công cụ khác vì căn chỉnh không được chỉ định sâu trong tiêu chuẩn ISO C (nó chỉ định rằng căn chỉnh có thể xảy ra tại trình biên dịch) nhưng không đi sâu vào chi tiết như thế nào để thực thi nó).

Bạn sẽ cần xem xét các công cụ triển khai cụ thể cho chuỗi công cụ biên dịch của mình. Nó có thể cung cấp #pragma pack (hoặc align hoặc một số thứ khác) mà bạn có thể thêm vào định nghĩa cấu trúc của mình.

Nó cũng có thể cung cấp điều này dưới dạng tiện ích mở rộng ngôn ngữ. Ví dụ, gcc cho phép bạn thêm các thuộc tính đến một định nghĩa, một trong số đó kiểm soát sự liên kết:

struct mystruct { int val[7]; } __attribute__ ((aligned (16))); 
11

Đối với Microsoft Visual C++:

#pragma pack(push, 16) 

struct _some_struct 
{ 
    ... 
} 

#pragma pack(pop) 

cho GCC:

struct _some_struct { ... } __attribute__ ((aligned (16))); 

Ví dụ:

#include <stdio.h> 

struct test_t { 
    int x; 
    int y; 
} __attribute__((aligned(16))); 

int main() 
{ 
    printf("%lu\n", sizeof(struct test_t)); 
    return 0; 
} 

được biên dịch với gcc -o main main.c sẽ xuất ra 16. Cũng vậy với các trình biên dịch khác.

+1

Đối với gcc __attribute__ được căn chỉnh, nó có thực sự buộc kích thước struct là bội số của 16B không? Hay nó chỉ đảm bảo rằng địa chỉ bắt đầu của cấu trúc được liên kết với 16B? –

+1

Cả địa chỉ xuất phát và kích thước của cấu trúc sẽ được căn chỉnh với 16B. Điều này được thực hiện để đảm bảo sự liên kết chính xác của các phần tử của mảng cấu trúc. – Romeo

+0

Điều này không đúng. Macro __attribute (aligned (x))) phân bổ cấu trúc trên một ranh giới x-byte và không có gì để làm với kích thước của cấu trúc http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc /Variable-Attributes.html –

3

Bạn có lẽ có thể làm một struct đôi, gói struct thực tế của bạn trong một giây có thể thêm padding:

struct payload { 
    int a; /*Your actual fields. */ 
    float b; 
    char c; 
    double d; 
}; 

struct payload_padded { 
    struct payload p; 
    char padding[16 * ((sizeof (struct payload) + 15)/16)]; 
}; 

Sau đó, bạn có thể làm việc với các cấu trúc đệm:

struct payload_padded a; 

a.p.d = 43.3; 

Dĩ nhiên , bạn có thể sử dụng thực tế là thành viên đầu tiên của cấu trúc bắt đầu 0 byte từ nơi cấu trúc bắt đầu và xử lý con trỏ đến struct payload_padded như thể đó là con trỏ đến struct payload (vì nó là):

float d_plus_2(const struct payload *p) 
{ 
    return p->d + 2; 
} 

/* ... */ 

struct payload_padded b; 
const double dp2 = d_plus_2((struct payload *) &b);