【问题标题】:Accessing array as a struct *将数组作为结构访问 *
【发布时间】:2011-05-29 13:28:25
【问题描述】:

这是其中之一我认为这应该可行,但最好检查问题。它可以在我的机器上编译并正常工作。

这是否保证符合我的预期(即允许我访问数组的前几个元素,并保证结构的布局、对齐、填充等与数组相同)?

struct thingStruct
{
    int a;
    int b;
    int c;
};


void f()
{
    int thingsArray[5];
    struct thingStruct *thingsStruct = (struct thingStruct *)&thingsArray[0];

    thingsArray[0] = 100;
    thingsArray[1] = 200;
    thingsArray[2] = 300;

    printf("%d", thingsStruct->a);
    printf("%d", thingsStruct->b);
    printf("%d", thingsStruct->c);
}

编辑:我到底为什么要做这样的事情?我有一个数组,我正在映射到一个文件。我将数组的第一部分视为“标题”,它存储有关数组的各种信息,其余部分我将其视为普通数组。如果我将结构指向数组的开头,我可以将标题数据作为结构成员访问,这样更具可读性。结构中的所有成员都与数组的类型相同。

【问题讨论】:

  • 认为只要你使用#pragma或其他东西来禁用结构上的填充就可以了。
  • 请注意,您可以使用 GCC 通过在结束结构定义的大括号后添加 __attribute__(packed) 来执行此操作。
  • 对于Windows编译器(GCC也支持),我相信你可以在struct定义前使用#pragma pack(0),在struct定义后使用#pragma pack()

标签: c arrays memory struct


【解决方案1】:

虽然我经常看到这样做,但您不能(意味着它不合法,标准 C)对结构的二进制布局做出假设,因为它可能在字段之间有填充。

comp.lang.c 常见问题解答中对此进行了解释:http://c-faq.com/struct/padding.htmls

【讨论】:

  • 你是对的......但我认为它应该在大多数情况下工作,除非编译器有某种理由在相同类型的项目之间添加填充。
【解决方案2】:

尽管它可能在大多数地方都有效,但它仍然有点不确定。如果您想为标题的某些部分赋予符号名称,为什么不这样做:

enum { HEADER_A, HEADER_B, HEADER_C };

/* ... */.

printf("%d", thingsArray[HEADER_A]);
printf("%d", thingsArray[HEADER_B]);
printf("%d", thingsArray[HEADER_C]);

【讨论】:

    【解决方案3】:

    正如 Evan 对问题所评论的那样,这可能在大多数情况下都有效(同样,如果您使用 #pragma pack 确保它们没有填充,这可能是最好的)假设您的结构中的所有类型都与您的数组类型相同。鉴于 C 的规则,这是合法的。

    我的问题是“为什么?”这不是一件特别安全的事情。如果一个浮点数被扔到结构的中间,这一切都会崩溃。为什么不直接使用结构?在大多数情况下,这确实不是我推荐的技术。

    【讨论】:

    • “鉴于 C 的规则,这是合法的。”这不违反严格的别名规则吗?
    • Hrm... 你认为它会,但 gcc 4.4.3 不会抱怨,无论我给它什么选择。可能是因为结构的第一个成员是正确的类型,因此没有冲突?我已经多次看到这种代码,其中一个较小的类型指向一个较大的值,每次都让我不寒而栗。
    • 为什么?我正在将数组映射到文件。我在开始时存储了一些标头信息,其余的我将其视为一个数组。所有值都属于同一类型(我不会梦想混合类型!)。我只是认为用描述性的 strut 成员对标题部分进行别名比索引更具可读性。
    • @Joe 关于较大/较小类型的评论与您的​​问题没有直接关系,它只是在讨论字符串别名时用作常见示例。
    • @Joe 抱歉,脑抽筋,您在原始答案中回答了我的“为什么”。在您描述的情况下,这听起来很合理。我可能会有点畏缩,但我可能会在代码审查中放手,只要有一些 cmets 解释发生了什么。也许您可以更新原始问题以描述您如何以及为什么要映射数组,这将使其他人更容易提供更具建设性的回应。
    【解决方案4】:

    另一种表示标题和其余文件数据的解决方案是使用如下结构:

    struct header {
        long  headerData1;
        int   headerData2;
        int   headerData3;
        int   fileData[ 1 ];  // <- data begin here
    };
    

    然后你用文件内容分配内存块并将其转换为struct header *myFileHeader(或将内存块映射到文件上)并使用

    访问所有文件数据
    myFileHeader->fileData[ position ]
    

    对于任意大的position。该语言对索引值没有限制,因此您只需将任意大 posistion 保持在您分配的内存块的实际大小(或映射文件的大小)内。 p>

    还有一个重要提示:除了关闭结构成员的填充外,其他人已经描述过,您应该仔细选择标题成员的数据类型,使其适合实际文件尽管您使用了编译器,但数据布局(例如,int 不会从 32 位更改为 64 位...)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-08
      • 2017-01-28
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      相关资源
      最近更新 更多