开发者

What's the difference between struct { ... } and struct { union { struct { ... } } }?

开发者 https://www.devze.com 2023-04-03 20:58 出处:网络
Is there a reason why DISK_DETECTION_INFO is defined as typedef struct _DISK_DETECTION_INFO { DWORDSizeOfDetectInfo;

Is there a reason why DISK_DETECTION_INFO is defined as

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;

instead of

typedef struct _DISK_DETECTION_INFO {
  DWORD          SizeOfDetectInfo;
  DETECTION_TYPE DetectionType;
  DISK_INT13_INFO    Int13;
  DISK_EX_INT13_INFO ExInt13;
} DISK_D开发者_JS百科ETECTION_INFO, *PDISK_DETECTION_INFO;

or am I just overanalyzing this piece of code?


Arguably, it's a mistake. However, it's possible that we're only given the public definition of the structure. Internally (when used by the Windows kernel), it might be defined as:

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;

I wouldn't volunteer this as maintainable, safe, or portable, but it's possible.

DISK_INTERNAL_INFO could even exceed the size of the anonymous struct - provided that a user is never instantiating the object themselves the technique might even be considered useful for hiding extra data away from the user but keeping it with the structure. They'd never "see" past the anonymous struct.


There is a very specific difference between the behaviors: in the first case, neither Int13 nor ExtInt13 are initialized when a DISK_DETECTION_INFO is initialized. In the latter case, all four fields are initialized.

MSVC has a slew of quirky extensions, including variable sized arrays at the end of structs, for which the automatic initialization behavior may be undesirable.

EDIT: about "initialization":

Let's say the struct was

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

Then, writing foo x = { 1; } does not assign a value to baz or wee (they are technically indeterminate). If the struct was

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

Then, writing foo x = { 1; } does assign baz=0 and wee=0


I think there's reasonable evidence that someone made a simple mistake when they wrote the original DISK_DETECTION_INFO struct definition. This mistake escaped into the wild and so it was too late to fix it.

The definition in the header file is:

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;

The documentation reads:

If DetectionType is DetectInt13, the union is a DISK_INT13_ INFO structure.

If DetectionType is DetectExInt13, the union is a DISK_EX_ INT13_INFO structure.

So it seems very likely that the original intention was for the DISK_INT13_INFO and DISK_EX_INT13_INFO to be placed in a union since they are mutually exclusive.


Union is usually use to save spaces when a group of fields have mutual exclusive access. That is, when one active, the other must not. As opposed to allocating space for all fields, the space is allocated only for the largest one. The space is used interchangably with other fields. As stated in the link, depending on DetectionType field it's either Int13 or ExInt13 is active. Both use the same allocated space.

0

精彩评论

暂无评论...
验证码 换一张
取 消