【问题标题】:C error: expression must have a constant valueC 错误:表达式必须有一个常量值
【发布时间】:2012-07-27 00:10:16
【问题描述】:

我正在编写一些嵌入式代码以通过 SPI 与外部设备进行交互。该设备有几个不同长度的寄存器,为了帮助保持正确,我定义了以下结构

typedef struct
{
    uint16_t    Signed          :1;  // Register is signed or unsigned
    uint16_t    CommLengthBytes :3;  // The width of the register in bytes 
    uint16_t    Address         :12; // Register address
}ts_register;

然后我在源代码中定义了每个寄存器,如下所示

static const ts_register    SAGCYC      = {0, 1, 0x000};
static const ts_register    DISNOLOAD   = {0, 1, 0x001};
static const ts_register    LCYCMODE    = {0, 1, 0x004};
static const ts_register    IRMSA       = {0, 4, 0x31A};
static const ts_register    IRMSB       = {0, 4, 0x31B};
static const ts_register    VRMS        = {0, 4, 0x31C};

等等

我有一个函数,它将获取一个指向 ts_registers 数组的指针,并将读取数组中所有寄存器所需的 SPI 传输排队,并调用回调函数来处理回复

当我尝试按如下方式制作我想要读取的 ts_registers 数组时,我的问题就出现了:

ts_register regs_to_read[3] = {VRMS, IRMSA, IRMSB};

这会产生错误:“表达式必须有一个常量值”3 次(每个数组元素一次)。

由于它们被定义为常量,我忽略了什么?

【问题讨论】:

  • 结构不是常量表达式(即使它们是const)。我认为在C++11中你可以用constexpr解决这个问题。但有更多知识的人会引用标准的相关部分。

标签: c arrays compiler-errors


【解决方案1】:

由于它们被定义为常量,我忽略了什么?

在使用 const 修饰符声明的 C 对象中不是真正的常量。更好的 const 名称可能是 readonly - 它的真正含义是编译器不会让 更改它。而且你需要真正的常量来初始化具有静态存储的对象(我怀疑regs_to_read 是全局的)。

您可以尝试在其他任何使用该数组之前调用的函数中分配regs_to_read

【讨论】:

  • @user812624 你确定这能解决你的问题吗?你应该不接受这个答案,看看是否有更好的东西出现。
  • 这个回复有点晚了,但是自从 16,000 人偶然发现了同样的问题,我将添加更多细节,说明为什么这是我的答案 -> VRMS,IRMSA IRMSB 可能不会一直是常数,但它们的地址是。我改用指针数组,这解决了我的问题。不是最优雅的,但它让我通过了那个障碍。此后代码被重构的次数超出了我的计算,并且与原始的 sn-p 没有任何相似之处,所以我无法展示最终的解决方案并让它帮助任何人
【解决方案2】:

const 不会在编译时使它们成为常量。使它们#defines 和编译器 会很开心。

【讨论】:

  • 不太正确,const int x = 3;x 将是一个常量表达式。
  • @KarolyHorvath 不,不会的。不在文件范围内。
  • 不在任何范围内。
【解决方案3】:

我认为这可能是编译器问题,了解您的平台以及如何构建此代码会很有帮助。我只是拿走了你的大部分代码,修改它来编译它,然后使用 gcc 在 Linux 上编译。没有警告。

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

typedef struct
{
    uint16_t    Signed          :1;  // Register is signed or unsigned
    uint16_t    CommLengthBytes :3;  // The width of the register in bytes 
    uint16_t    Address         :12; // Register address
}ts_register;

int main(int argc, char **argv) {

    static const ts_register    SAGCYC      = {0, 1, 0x000};
    static const ts_register    DISNOLOAD   = {0, 1, 0x001};
    static const ts_register    LCYCMODE    = {0, 1, 0x004};
    static const ts_register    IRMSA       = {0, 4, 0x31A};
    static const ts_register    IRMSB       = {0, 4, 0x31B};
    static const ts_register    VRMS        = {0, 4, 0x31C};

    ts_register regs_to_read[3] = {VRMS, IRMSA, IRMSB};

    return(0);
}

您是否尝试过强制转换值?这并不总是最好的做法,但会让你绕过错误。

您是否考虑过创建#define 条目?

另外,请注意 const 在 C 中需要一点时间来适应。它们的行为并不总是如您所愿。

【讨论】:

  • 在您的代码中,ts_register 是一个自动对象。我怀疑它在 OP 发布的代码中有静态存储。
  • 是的,在 OP 中获得完整的列表会很好。
  • 通过强制转换来绕过错误从来都不是一个好方法。理解为什么会有警告是最重要的。然后修复代码,在 100 种情况下,有 99 种情况下你可以在没有演员表的情况下完成。演员阵容通常是一种代码味道。
  • 我在 Keil IDE 中使用 ARM 的编译器。当文件编译为 c 时,您的代码列表会产生相同的错误,但编译为 cpp 时不会出现错误,我猜这突出了语言之间的一些细微差别。
  • 我在 Google 中找到了这个 Q/A 很有趣,因为我也遇到了 Keil 编译器的错误。
【解决方案4】:

如果在任何函数范围内声明regs_to_read,错误将被清除。

【讨论】:

    猜你喜欢
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 2021-01-14
    • 2020-03-07
    相关资源
    最近更新 更多