В чем разница между struct {...} и struct {union {struct {...}}}? - PullRequest
5 голосов
/ 11 сентября 2011

Есть ли причина, по которой DISK_DETECTION_INFO определяется как

typedef struct _DISK_DETECTION_INFO {
  DWORD          SizeOfDetectInfo;
  DETECTION_TYPE DetectionType;
  union {
    struct {
      DISK_INT13_INFO    Int13;
      DISK_EX_INT13_INFO ExInt13;
    };
  };
} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO;

вместо

typedef struct _DISK_DETECTION_INFO {
  DWORD          SizeOfDetectInfo;
  DETECTION_TYPE DetectionType;
  DISK_INT13_INFO    Int13;
  DISK_EX_INT13_INFO ExInt13;
} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO;

или я просто переоцениваю этот кусок кода?

Ответы [ 4 ]

6 голосов
/ 11 сентября 2011

Возможно, это ошибка.Тем не менее, возможно , что нам дано только публичное определение структуры.Внутренне (при использовании ядром Windows) это может быть определено как:

typedef struct _DISK_DETECTION_INFO {
  DWORD          SizeOfDetectInfo;
  DETECTION_TYPE DetectionType;
  union {
    struct {
      DISK_INT13_INFO    Int13;
      DISK_EX_INT13_INFO ExInt13;
    };
    DISK_INTERNAL_INFO   Private; // Used internally, when DetectionType = -1
  };
} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO;

Я бы не назвал это обслуживаемым, безопасным или переносимым, но это возможно .

DISK_INTERNAL_INFO может даже превышать размер анонимного struct - при условии, что пользователь никогда не создает экземпляр объекта самостоятельно, эту технику можно даже считать полезной для сокрытия дополнительных данных от пользователя, но хранения их с помощьюсостав.Они никогда не "видят" мимо анонима struct.

0 голосов
/ 11 сентября 2011

Я думаю, что есть разумные доказательства того, что кто-то допустил простую ошибку, когда написал первоначальное определение структуры DISK_DETECTION_INFO. Эта ошибка вырвалась в дикую природу, и было слишком поздно, чтобы исправить это.

Определение в заголовочном файле:

typedef struct _DISK_DETECTION_INFO {
        DWORD SizeOfDetectInfo;
        DETECTION_TYPE DetectionType;
        union {
                struct {

                        //
                        // If DetectionType == DETECTION_INT13 then we have just the Int13
                        // information.
                        //

                        DISK_INT13_INFO Int13;

                        //
                        // If DetectionType == DETECTION_EX_INT13, then we have the
                        // extended int 13 information.
                        //

                        DISK_EX_INT13_INFO ExInt13;     // If DetectionType == DetectExInt13
                } DUMMYSTRUCTNAME;
        } DUMMYUNIONNAME;
} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO;

Документация гласит:

Если для DetectionType установлено значение DetectInt13, объединение представляет собой структуру DISK_INT13_ INFO.

Если DetectionType имеет тип DetectExInt13, объединение представляет собой структуру DISK_EX_ INT13_INFO.

Таким образом, представляется весьма вероятным, что первоначальное намерение состояло в том, чтобы DISK_INT13_INFO и DISK_EX_INT13_INFO были объединены в союз, поскольку они являются взаимоисключающими.

0 голосов
/ 11 сентября 2011

Существует очень специфическое различие между поведением: в первом случае ни Int13, ни ExtInt13 не инициализируются при инициализации DISK_DETECTION_INFO.В последнем случае все четыре поля инициализируются.

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

РЕДАКТИРОВАТЬ: об "инициализации":

Допустим, структура была

typedef struct _foo {
  int bar;
  union {
    struct {
      int baz;
      int wee;
    };
  };
} foo;

Затем, запись foo x = { 1; } не присваивает значение baz или wee (они технически не определены).Если структура была

typedef struct _foo {
  int bar;
  int baz;
  int wee;
} foo;

Тогда, при написании foo x = { 1; } присваивается baz = 0 и wee = 0

0 голосов
/ 11 сентября 2011

Объединение обычно используется для сохранения пробелов, когда группа полей имеет взаимоисключающий доступ.То есть когда один активен, другой не должен.В отличие от выделения места для всех полей, пространство выделяется только для самого большого.Пространство используется взаимозаменяемо с другими полями.Как указано в ссылке, в зависимости от поля DetectionType активен либо Int13, либо ExInt13.Оба используют одинаковое выделенное пространство.

...