используя потраченное впустую пространство - PullRequest
1 голос
/ 27 июля 2011

Следующая структура X имеет 3 байта полезной нагрузки и 1 байт заполнения:

struct X
{
    short a;
    char b;
};

memory layout: aab.

Следующая структура Y имеет 4 байта полезной нагрузки и 2 байта заполнения:

struct Y
{
    X x;
    char c;
};

memory layout: aab.c.

Есть ли способ сохранить X вложенным внутри Y и иметь sizeof(X) == 4 && sizeof(Y) == 4?

memory layout: aabc

В идеале, я хотел бы, чтобы этот вид оптимизации пространства для всех типов X (думаю X в качестве параметра шаблона).

Ответы [ 5 ]

1 голос
/ 27 июля 2011

Это настройка компилятора.Заполнение необходимо для правильной работы доступа к памяти в некоторых случаях.В некоторых архитектурах это вопрос эффективности, в других программа будет аварийно завершена, если не будет правильно выровнена.В этом случае у вас есть 16-битное выравнивание, и прямой доступ к c по нечетному адресу может вызвать проблемы.

Однако вы можете принудительно отключить выравнивание, используя pack pragma (или любой другой вариант, который есть у вашего компилятора).

Вопрос в том, почему.Если вы полагаетесь на это - вы делаете свою программу потенциально непереносимой и непредсказуемой для различных архитектур.

0 голосов
/ 27 июля 2011

По понятным и понятным причинам, размер X и Y не может быть равным четырем (если бы это было возможно, X имел бы несколько определений, обычное заполненное одно и одно, где заполнение используется char из Y). Таким образом, единственный способ Y может быть равен 4, если X были изменены, чтобы исключить его заполнение. Это может быть сделано с помощью специальных прагм или директив компилятора. Тем не менее, поскольку это может привести к тому, что к X будет получен доступ без выравнивания, это фактически ограничит возможную переносимость вашей программы (некоторые архитектуры могут даже потерпеть крах, если будут выполнены смещенные обращения).

Вместо этого, вы можете более четко объяснить конечный результат, который вы надеетесь достичь здесь?

0 голосов
/ 27 июля 2011

Да, но это не стандартный C / C ++ и требует специфичных для компилятора расширений. Для MSVC используйте pack pragma :

#pragma pack(push, 1)
struct X 
{
    ...
};
#pragma pack(pop)

Для GCC используйте атрибут типа packed :

struct __atribute__((packed)) X
{
    ...
};

С некоторыми макросами препроцессора и токеном __pragma вы можете выполнить определение в обоих компиляторах, не требуя набора #if условий.

0 голосов
/ 27 июля 2011

В gcc вы можете объявить свою структуру, используя ключевое слово __attribute__((packed)), чтобы поддерживать определенное выравнивание байтов или заполнение.

Так, например, вы можете сделать что-то вроде

typedef struct X
{
    short a;
    char b;
} __attribute__((packed)) X;

typedef struct Y
{
    X x;
    char c;
} __attribute__((packed)) Y;

Теперь sizeof(Y) будет 4 байта ... единственная проблема заключается в том, что вы заплатите штраф за производительность за любую распаковку, которая должна быть выполнена, чтобы соответствовать требованиям выравнивания байтов вашей аппаратной платформы.

0 голосов
/ 27 июля 2011

Вы можете принудительно настроить выравнивание с помощью прагмы:

#pragma pack(push, 1)
struct X
{
    short a;
    char b;
};
#pragma pack(pop)

Это поддерживается компилятором Microsoft C ++. Я не знаю, является ли это портативным способом выполнения этого.

...