如何在记录结构内声明并集?

Joh*_*ony 6 delphi winapi delphi-7

我正在尝试定义TWaveFormatExtensible类型,但是我不确定是否正确声明了Samples联合。这是头文件(Windows SDK 10.0.17763.0)中的原始声明:

typedef struct {
    WAVEFORMATEX    Format;
    union {
        WORD wValidBitsPerSample;       /* bits of precision  */
        WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
        WORD wReserved;                 /* If neither applies, set to zero. */
    } Samples;
    DWORD           dwChannelMask;      /* which channels are */
                                        /* present in stream  */
    GUID            SubFormat;
}
Run Code Online (Sandbox Code Playgroud)

这就是我尝试过的:

type
  TWAVEFORMATEX = record
    wFormatTag: Word;
    nChannels: LongWord;
    nSamplesPerSec: Word;
    nAvgBytesPerSec: LongWord;
    nBlockAlign: Word;
    wBitsPerSample: Word;
    cbSize: Word;
  end;

  TWaveFormatExtensible = record
    Format: TWAVEFORMATEX;
    dwChannelMask: LongWord;
    SubFormat: Integer;
    case Word of
      0: (wValidBitsPerSample: Word;);
      1: (wSamplesPerBlock: Word;);
      2: (wReserved: Word;);
  end;
Run Code Online (Sandbox Code Playgroud)

但这是不正确的。如何在Delphi的记录结构中声明联合?

Tom*_*erg 11

The fields of the structure must be in the same order as in the original (C++) declaration. But there's a problem: the original declaration puts the Samples variant in the middle of the record and that is not allowed in Delphi.

You can solve this by declaring the variant part as a separate record and then include that record as a field in the final structure.

TWaveFormatExtensibleSamples = record
case Word of
  0: (wValidBitsPerSample: Word;);
  1: (wSamplesPerBlock: Word;);
  2: (wReserved: Word;);
end;
Run Code Online (Sandbox Code Playgroud)

and then construct the final structure:

TWaveFormatExtensible = record
  Format: TWAVEFORMATEX;
  Samples: TWaveFormatExtensibleSamples;
  dwChannelMask: DWORD;
  SubFormat: TGUID; 
end;
Run Code Online (Sandbox Code Playgroud)

edit: The documentation for records with variant parts, state:

A record type can have a variant part, which looks like a case statement. The variant part must follow the other fields in the record declaration.

This concerns variant parts without an enclosing record declaration.

However, as Remy Lebeau pointed out, a record with the variant part can be directly declared in the TWaveFormatExtensible declaration as part of the structure, in between other fields:

TWaveFormatExtensible = record
  Format: TWAVEFORMATEX;
  Samples: record
    case Word of
    0: (wValidBitsPerSample: Word;);
    1: (wSamplesPerBlock: Word;);
    2: (wReserved: Word;);
  end;
  dwChannelMask: DWORD;
  SubFormat: TGUID;
end;
Run Code Online (Sandbox Code Playgroud)

So this can be used as well as the separately declared TWaveFormatExtensibleSamples record.

  • 在这种情况下,因为`Samples`在C声明中不是匿名联合,所以您可以将`TWaveFormatExtensibleSamples`直接合并到`TWaveFormatExtensible`中,不需要将其分开:`TWaveFormatExtensible = record ... Samples:记录案例...结束的话 ...结束;` (4认同)