【问题标题】:How to "extend" struct in C?如何在 C 中“扩展”结构?
【发布时间】:2015-08-05 19:01:17
【问题描述】:

我想根据某个值从文件中读取不同的数据结构。在某些解释语言中,我可以执行类似于以下代码的操作。在 C++ 中,我会扩展 WindowsOptions 类。但是出于某种原因,我选择了 C。我可以为每种情况编写两个单独的代码块。我还有其他选择吗?这个问题可能很愚蠢,但你对那个 HTML 人有什么期望。

if(options.signature == 0x20b) {
    PEOptionsHeaderWindowsPlus windowsOptions;
} else {
    PEOptionsHeaderWindows windowsOptions;
}
fread(&windowsOptions, sizeof(windowsOptions), 1, file);
printf("%hu", windowsOptions.MajorOsVersion);

【问题讨论】:

  • 您的代码无法编译,sizeof(windowsOptions) 无法工作,因为windowsOptions 超出范围。也就是说,PEOptionsHeaderWindows 的定义是什么? C/C++ 中的大多数 PODO 将包含 cbSize 或类似成员,以允许保存运行时大小信息。

标签: c data-structures scope


【解决方案1】:

用另一个包裹起来怎么样?

typedef struct structA{
  int x;
  int y;
}A;

typedef struct structB{
  A *a;
  int z;
}B;

注意:记住在structB中初始化A指针。

更新:另一种选择是使用两种类型的联合:

typedef struct structA{
  int x;
  int y;
}A;

typedef struct structB{
  int z;
}B;

union AB {
  A* a;
  B* b;
} ABUnion;

【讨论】:

  • 我认为这两个选项中的union 会更好,因为它浪费的空间更少。
  • 确实,添加到答案中。
【解决方案2】:

由于struct 的头部不能有填充,因此共享相同(或兼容)第一个字段的两个structs 对于该部分是兼容的。例如,各种 sockaddr 类型(第一个字段是地址类型,其余字段取决于该字段的值)使用了这个技巧。

以下是如何在您描述的场景中使用此属性的示例:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define common_fields \
    int value; \
    bool is_plus

struct base_type {
    common_fields;
};

struct plus_type {
    common_fields;
    int plus_value;
};

static void print_struct (const struct base_type * const p) {
    (void) printf("value = %d\n", p->value);
    if (p->is_plus) {
        const struct plus_type * const plus = (struct plus_type *)p;
        (void) printf("plus_value = %d\n", plus->plus_value);
    }
}

int main (int argc, char *argv[]) {
    struct base_type *p;
    if (argc > 1) {
        p = malloc(sizeof(struct plus_type));
        p->is_plus = true;
    } else {
        p = malloc(sizeof(struct base_type));
        p->is_plus = false;
    }
    p->value = 6;
    if (p->is_plus) {
        ((struct plus_type *)p)->plus_value = atoi(argv[1]);
    }
    print_struct(p);
    free(p);
    return EXIT_SUCCESS;
}

common_fields 宏用于避免两次键入公共字段。许多流行的编译器都有一个扩展,允许执行以下操作:

struct base_type {
    int value;
    bool is_plus;
}

struct plus_type {
    struct base_type;
    int plus_value;
};

对于clanggcc,此扩展由-fms-extensions 启用。

请注意,在使用此技巧时,您必须注意分配 struct 的正确大小。或者,您可以在struct base_type 的末尾添加额外的字段(例如char 的数组),使其至少与struct plus_type(以及共享相同基本类型的任何其他structs)一样大,但在这种情况下,union 解决方案可能会更好。

【讨论】:

  • 有趣的解决方案。所有答案都需要一些额外的逻辑。我的结构相交并有一些不同大小的字段。我把它简单化了。分别读取每个结构并写入第三个以供以后使用。
【解决方案3】:

以下建议的代码处理支柱大小和任何错误情况

struct shortStruct
{
    int field1;
};

struct longStruct
{
    int field1;
    int field2;
};

char buffer[sizeof(longStruct)+1];

memset( buffer, '\0', sizeof(longStruct) );
if ( 0x020b == options.signature  )
{
    byteCount = read( fd, buffer, sizeof( struct shortStruct ) );
}
else
{
    byteCount = read( fd, buffer, sizeof( struct longStruct );
}

switch( byteCount )
{
    case sizeof(longStruct):
        // process long struct fields
        break;

    case sizeof(shortStruct):
        // process short struct fields
        break;

    default:
        // process the error
        break;
} // end switch

【讨论】:

    猜你喜欢
    • 2014-04-08
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多