【问题标题】:GCC array default fill valueGCC 数组默认填充值
【发布时间】:2015-07-12 18:46:35
【问题描述】:

问题简述

我最近发现了一个 gcc 扩展,我发现它非常酷且很有帮助。这允许您指定初始化元素在数组中的索引。所以不是

static const uint8_t array[4] = {
    2,
    1,
    3,
    4
};

一个人会写

static const uint8_t array[4] = {
    [1] = 1,
    [0] = 2,
    [2] = 3,
    [3] = 4
};

但是,通常我有一个数组,我有一个或两个需要不同的特定值,而数组的其余部分设置为某个默认值。我希望能够在初始化程序中完成这一切;像

static const uint8_t array[4] = {
    [1]               = 1,
    [everything else] = 0
};

有人知道这样做的好方法吗?我想出的唯一方法(这似乎有点 hacky)是定义一个 EVERYTHING_ELSE 宏,它依赖于相同的值和数组长度——像这样:

#define VALUE                            (8)
#define DEFAULT                          (1)
#define INDEX                            (2)
#define ARRAY_LENGTH                     (4)
#define EVERYTHING_ELSE(n, index, len)   (((index) + (n)) % (len))

static const uint8_t array[ARRAY_LENGTH] = {
    [EVERYTHING_ELSE(1, INDEX, ARRAY_LENGTH)] = DEFAULT,
    [EVERYTHING_ELSE(2, INDEX, ARRAY_LENGTH)] = DEFAULT,
    [EVERYTHING_ELSE(3, INDEX, ARRAY_LENGTH)] = DEFAULT,
    [INDEX]                                   = VALUE;
}; 

一点背景

我从事嵌入式系统编程,这通常意味着配置外围设备。在这种特殊情况下,数组的每个元素可能对应于外围设备中的一个通道。如果我正在为不同的电路板构建一个项目,引脚分配略有不同,我可能会在不同的情况下使用不同的通道。为了帮助加强正确性和可移植性,我更喜欢在一个地方定义这个值,并编写依赖于这个值的代码。

此外,我需要确保该特定外围设备中的所有其他通道都已停用。在上面的示例中,我有一个简单的整数数组,但通常情况更复杂(它是一个初始化结构数组,或类似的东西)。我知道默认情况下静态数组将初始化为零,但零对应于未初始化的情况并不总是如此;此外,我认为将库常量作为正确运行代码的特定值是一种不好的形式。

我可以使数组非常量并在运行时进行初始化,但在嵌入式系统中这可能是个问题。如果您只有 6k 的 RAM,那么有强烈的动机将所有可以在编译时确定的内容放入闪存中,以便为实际需要在运行时改变的内容留出最大的 RAM 空间。

【问题讨论】:

  • 好吧,如果您希望除少数几个值之外的所有值都初始化为零,那么为什么不将其初始化为零,然后在一些初始化例程中将少数特定值设置为应有的值?
  • 零初始化“其他一切”很简单:int a[5] = {[2]=5}; 和其余元素(第三个元素除外)被隐式设置为 0。但是要使用不同的值进行初始化,您必须使用一些技巧像你一样。
  • 您可以使用“另一个”GNU 扩展:uint8_t array[4] = { [0 ... 3] = DEFAULT, [1] = 1 };
  • @cremno 实际上 OP 是标准 C 的一部分。只有您建议的范围初始化程序是 gcc 扩展。考虑到他似乎对扩展没问题,你的建议可能就是他想要的。
  • @JoachimPileborg 我不想这样做,因为这会迫使数组进入 RAM,在我的用例中这是不可接受的(请参阅最后的文字墙)

标签: c arrays gcc embedded


【解决方案1】:

这不是 gcc 专业,而是自 C99 以来的标准功能,称为 designated initializer。结构字段也是可能的(这与强调 imo 更相关)。

请注意,该标准仅允许指定单个索引(使用 常量表达式),而不是范围,即 gcc 扩展。也没有标准方法可以将“所有其他”字段设置为 0 以外的值(浮点数/复数为 0.0,指针为 NULL)。

按照标准的定义,未显式初始化的字段/元素设置为 0。但是,如果您有一个较大的数组,其中很少有设置为非 0 的字段,您应该从代码中显式设置这些字段(如果对象当然不是const)。原因是 0 初始化的全局对象不消耗 ROM/Flash/文件空间,而非零初始化对象的初始化程序必须显式存储 - 完全。对于嵌入式系统,这显然不是一个好主意。

如果您必须设置一个大数组,最好通过一个小程序创建一个包含该数组的 C 源代码文件(我使用 Python,因为这很简单)。然后,此文件可以在您的程序代码中为#include(如果为static),或者与您的预编程文件一起编译/链接为任何其他源代码。

【讨论】:

    猜你喜欢
    • 2014-01-31
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2019-09-26
    相关资源
    最近更新 更多