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.
精彩评论