2015-02-08 6 views
1

Я читал, что в Союзах члены данных занимают один и тот же блок памяти. Итак, я попытался прочитать ASCII-коды английского алфавита, используя эту реализацию.Хранение союза в памяти

union { 
    int i; 
    char a,b; 
}eps; 
eps.i=65; 
cout<<eps.a<<eps.b; 

Я получил правильный выход (A) для 65, но, как и ab, кажется, занимают такое же место в памяти.

Q. Но целое число, равное 2 байтам, не должно a заняло первые 8 бит и b других 8?

Кроме того, повторяя вышеизложенное с несколькими целыми числами внутри объединения, они, похоже, имеют одинаковое значение.

Q. Значит ли это, что каждая переменная данного типа данных действует как ссылку для любой другой переменной для одного и того же типа данных? (Учитывая простое добавление к переменным int i,j,k,l.....)

Q. Можно ли использовать только одну (отличную) переменную данного типа данных в объединении, поскольку все остальные указывают на одно и то же местоположение?

EDIT

Я хотел бы отметить, что при добавлении в любых более переменных внутри союза, это просто означает, добавив их как int i,j,k... не используя оборачивать их внутри struct или каким-либо другим способом.

Как уточнил Baum mit в чате (и комментарии), Here's the discussion для других пользователей/будущих пользователей.

+0

Используйте анонимную структуру для обертывания a и b. – didierc

+2

'char a, b' является просто сокращением для' char a; char b; ' – Dave

+0

Я знаю, что @Dave –

ответ

7

Чтение члена union, который не является тем, который вы в последний раз писали, является неопределенным поведением. Это означает, что ваш код может что-то сделать, и спорить о его поведении не имеет смысла.

Для преобразования между типами используйте appropriate cast, а не союз.

Чтобы ответить на ваши вопросы после редактирования:

Q. Но целое число, равное 2 байта, не занимали первые 8 бит и б другой 8?

Как вы сказали, каждый член профсоюза разделяет одно и то же пространство. Поскольку a и b являются разными членами, они имеют одинаковое пространство (в том смысле, что они оба живут где-то в пространстве, принадлежащем объединению). Фактическое расположение союза может выглядеть следующим образом:

byte 0 | byte 1 | byte 2 | byte 3 
i  i  i  i 
a 
b 

Q. Таким образом, это означает, что, что каждая переменная данного типа данных выступает в качестве ссылки для любой другой переменной для одного типа данных?

Нет, то количество экземпляров не совпадает с указанным артистом. Если у вас есть ссылка на объект, вы можете надежно получить доступ к этому объекту через ссылку. Два члена того же типа, вероятно, будут использовать точную память , но вы не можете положиться на это. Правило, о котором я говорил выше, по-прежнему применяется.

В. Можно ли использовать только одну (отличную) переменную данного типа данных в объединении, поскольку все остальные указывают на одно и то же местоположение?

У вас может быть столько же участников, как вы хотите. Они могут или не могут жить в той же самой памяти. Это не имеет значения, потому что вы можете получить доступ только к последнему, написанному в любом случае.

+0

......... Что? –

+0

Это означает, что этот подход никогда не должен использоваться. – drescherjm

+0

@KunalGupta После того, как вы напишете на 'eps.i', вам ** ** ** разрешено читать' eps.i', пока вы не напишете другому участнику. Тогда вы можете прочитать ** только ** тот. –

3

Напомним, что тип union представляет собой набор альтернативных возможностей. Формальная формулировка заключается в том, что это сопутствующий продукт всех типов, к которым принадлежат его поля.

union { 
    int i; 
    char a,b; 
} 

синтаксически эквивалентно:

union { 
    int i; 
    char a; 
    char b; 
} 

a и b существо одного и того же типа, что они не способствуют более вместе, чем друг от друга взятые по отдельности. Другими словами, b является избыточным.

Вам нужно обернуть a и b полей в struct, чтобы получить их в комплекте в качестве одной альтернативы union.

union { 
    int i; 
    struct { 
    char a; 
    char b; 
    }; 
} 

Кроме того, int типа на большинстве платформ это 32 бита интегрального типа и char 8 битную интегрального типа - я говорю обычно, потому что размеры не формально определены не только с точки зрения int больше или равно char.

Таким образом, предполагая, что мы имеем обычные определения для char и int, второй альтернативного быть 16 битными, компилятор имеет возможность разместить его там, где он хочет, чтобы в том же пространстве, занимаемом большим поле (32 бит).

Другая проблема - это порядок байтов, который может отличаться от одной платформы к другой.

Вы могли бы, возможно, получить его на работу (а на практике это почти всегда работает) путем наложения-структуры с пропущенными байтами до 32 бита:

union { 
    int i; 
    struct { 
    char a; 
    char b; 
    char c; 
    char d; 
    }; 
} 

(думать о int представления адреса IPv4 например, и функцию htons, чтобы покрыть проблему порядка байтов).

Однако окончательное правило диктуется спецификациями языка C, которые не указывают эту точку.

Чтобы быть в безопасности, вместо того, чтобы использовать union, я хотел бы выполнить набор функций, чтобы вытащить байты по битовому маскированию, но если вы ориентируетесь на определенную платформу, и вышеупомянутый союз работает ...

+0

И как это помогает? –

+3

Обратите внимание, что, как сказал Баум, это все равно не позволит вам установить 'i', затем читать' a' или 'b', это просто означает, что вы можете хранить значения для' a' и 'b' одновременно, ИЛИ значение для 'i'. Вы все еще не можете (надежно) установить 'i', затем прочитать' b'. – Dave

+0

@Dave Есть IMHO одно предостережение этому неопределенному поведению правила, которое, когда «унифицированные» типы имеют одинаковый размер байта (вне соображений выравнивания). Как мог компилятор сделать иначе, чтобы поставить оба представления для одной и той же последовательности байтов в разных пространствах? Если вы помещаете int и float * alone * в объединение, я не вижу, как компилятор испортит это с практической точки зрения. – didierc

3

Вы неправильно поняли, для чего предназначены профсоюзы. Они не дают никаких гарантий относительно совместного использования памяти любым предсказуемым способом. Они просто предоставляют способ сказать, что сущность может хранить один из нескольких типов информации. Если вы установите один тип, другие не определены (может быть что угодно, даже что-то не связанное с данными, которые вы вставляете). Как они обмениваются памятью с компилятором и могут зависеть от оптимизаций, которые включены (например, правила выравнивания памяти).

Сказав все это, в большинстве ситуаций (и при оптимизации отключены) вы обнаружите, что каждая часть объединения начинается с байта 0 объединения (не полагается на это). В вашем коде union{int i;char a,b;} говорит, что «этот союз может быть целым числом i, или char a, или char b». Вы могли бы использовать (как многие предложили), union{int i;struct{char a,b;}}, которые сказали бы компилятору: «этот союз может быть целым числом i, или это может быть структура символов a и b».

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

Итак, где бы вы использовали союз? Вот пример:

struct { 
    int type; // maybe 0 = int, 1 = long, ... 
    union { 
     char c; 
     int i; 
     long l; 
     float f; 
     double d; 
     struct { 
      int x; 
      int y; 
     } pos; 
     // etc. 
    } value; 
}; 

С объектом, как это, мы можем динамически хранить числа любого типа (или то, что мы могли бы, как 2D позиция в данном примере), сохраняя при этом, что на самом деле там используя внешняя переменная. Он использует гораздо меньше памяти, чем эквивалентный код без объединения, и делает настройку/получение безопасности (нам не нужно указывать указатели повсюду)

Смежные вопросы