当前位置: 首页 > 知识库问答 >
问题:

我需要在C预处理器中找到一种方法来测试一个值是否会创建一个0大小的数组

张逸清
2023-03-14

我有一个结构,必须垫出来64K,以完美地适应一个嵌入式项目,所以它填充了一个闪存块。所以有一个#定义,它使用sizeof()将结构中的元素相加,并确定末尾的pad[]需要多大才能使总大小64K。

例如:

#define SIZE_OF_MY_PAD (0x10000 - (sizeof(uint16_t) + sizeof(uint8_t)*32 + ... ))

typedef struct {
  uint16_t firstElement;
  uint8_t  secondElementArray[32];
  ...
  uint8_t pad[SIZE_OF_MY_PAD];
};

这在很长一段时间内都非常有效,直到突然我们在某些构建配置中根本不需要pad,因为它已经精确到64k了。这会导致代码失败,因为我们的编译器(不是GCC)不允许pad[0]

我尝试了各种方法来创建一个预处理器值,当检测到该值时,我可以在#if语句中使用它,但它总是失败,因为尽管sizeof()#define中是合法的,但在#if中是不合法的。

共有1个答案

郎祯
2023-03-14

借助C11中引入的匿名结构,无需任何预处理器即可解决此问题。

将flash类型定义为包含嵌入到匿名结构中的成员的联合。使char_pad[0x10000]联合的另一个成员,以强制引入类型的总大小。

typedef union {
    struct {
        uint16_t firstElement;
        uint8_t  secondElementArray[32];
        float thirdElement;
    };
    char _pad[0x10000];
} flash_t;

此解决方案对结构成员布局的任何修改都具有鲁棒性。此外,这避免了定义C标准技术上禁止的零长度数组的问题(尽管GCC允许)。此外,还可以添加一个静态断言来检查闪存的最大大小是否溢出。

示例程序:

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

typedef union {
    struct {
        uint16_t firstElement;
        uint8_t  secondElementArray[32];
        float thirdElement;
        // int kaboom[20000]; // will trigger assert if uncommented
    };
    char _pad[0x10000];
} flash_t;

_Static_assert(sizeof(flash_t) == 0x10000, "Oops, flash_t got too large");

int main() {
    flash_t flash;
    printf("offsetof(flash.firstElement) = %zi\n", offsetof(flash_t, firstElement));
    printf("offsetof(flash.secondElementArray) = %zi\n", offsetof(flash_t, secondElementArray));
    printf("offsetof(flash.thirdElement) = %zi\n", offsetof(flash_t, thirdElement));
    printf("sizeof(flash) = %zi\n", sizeof flash);
    return 0;
}

产生预期产出:

offsetof(flash.firstElement) = 0
offsetof(flash.secondElementArray) = 2
offsetof(flash.thirdElement) = 36
sizeof(flash) = 65536

>

  • 正如注释中建议的,联合成员_pad可以重命名为_rawData,因为_pad的语义学不同于问题中的pad

    如果需要类型中的成员pad,则可以将其作为灵活成员添加到匿名结构的末尾。

    typedef union { struct { ...; uint8_t pad[]; }; char _rawData[0x10000]; } flash_t;
    

  •  类似资料:
    • 我有一个结构,必须扩展到64K,以完美地适合嵌入式项目,使它填补一个闪存块。因此有一个#define,它使用sizeof()将结构中的元素相加,并确定末端的pad[]需要多大才能使总大小达到64K。 例如, 这已经工作了很长一段时间,直到突然间,我们在某些构建配置中根本不需要pad,因为它已经完全是64K了。这会导致代码失败,因为我们的编译器(不是GCC)不允许pad[0]。我尝试了各种方法来创建

    • 基本上,我需要这样的行列表: [0,0] [1,0],[0,1] [2,0],[1,1],[0,2] [3,0],[2,1],[1,2],[0,3] [4,0],[3,1],[2,2],[1,3],[0,4] 最多可添加任意数量的元素,然后再返回 [4,1],[3,2],[2,3],[1,4] [4,2],[3,3],[2,4] [4,3],[3,4] [4,4] 我只是希望所有这些对都在一个大的

    • 我需要创建一个带有签名的方法 此方法访问数组中的每个对象,并对属性租金求和并返回总金额。报税表:总租金 这是我的密码: 这是正确的吗?它一直说没有使用total变量,所以我不确定我是否做对了。

    • 问题内容: 我经常发现自己需要过滤a 或使用谓词来检查给定字段是否具有给定值。 比如说我有这个POJO: 我想根据的值过滤对象的: 是否会有一种方便的方法来为该方法生成谓词?我注意到有,但不符合需要。 我可以很容易地这样写: 并将其用作: 但我希望尽可能重用JDK中的现有方法。 问题答案: 没有内置的工厂方法,您可以通过查看JFC中的所有用法并查找“ …中返回谓词的方法” 来轻松检查。除了自身内部

    • 问题内容: 所以,我不确定那是什么。如果在 ModuleA中 ,我有: 在 ModuleB中 ,我有: 在主程序中,我有: 因此,当我运行主程序时,我想我将创建两个猫鼬“实例”;一个连接到pathA,一个连接到pathB,对吗? 另外,在模块B中,在我连接到pathB之前,它是连接到pathA还是什么都没有? 谢谢。 问题答案: 我刚刚对最新的节点V0.4.6做了一些测试。我确认了以下内容: 从“

    • 问题内容: 我有一个。如果用户第二次输入相同的数字,我想向用户显示。为此,我需要找到它。 我希望我能说清楚。 问题答案: 如果要检查是否在中存储了某些值,则可以使用该方法,如果对象在列表中,则将返回该方法,否则。