Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C error: expression must have a constant value

I am writing some embedded code to interface with an external device over SPI. The device has several registers of varying length and to help keep things straight I have defined the following structure

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;

I have then defined each register in my sources as follows

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};

etc.

I have a function that will take a pointer to an array of ts_registers and queue up the SPI transfers required to read all of the registers in the array and call a callback function to handle the reply

My issue comes when I try to make the array of ts_registers that I want to read as follows:

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

This generates the error: "expression must have a constant value" 3 times (once per array element).

Since they are defined as constants, what have I overlooked?

like image 420
user812624 Avatar asked Jul 28 '12 16:07

user812624


People also ask

Can constant variables be used in constant expressions?

Unfortunately constant variables cannot be used in constant expressions. They are considered to be variables that cannot change, but not constants that can be determined at compile time.

What is the difference between integer constant expressions and const qualified variables?

Unfortunately, C makes a difference between integer constant expressions and " const qualified" variables. (C and C++ are different here.) This means that the initializer of your cfg variable must be an integer constant (for example 1 ), an enum or a #define value, or an expression formed by such operands.

What are constant expressions in an initializer?

4 All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals. 2 A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.

When to use a constant expression in a translation?

2 A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be. 7 More latitude is permitted for constant expressions in initializers.


3 Answers

Since they are defined as constants, what have I overlooked?

In C objects declared with the const modifier aren't true constants. A better name for const would probably be readonly - what it really means is that the compiler won't let you change it. And you need true constants to initialize objects with static storage (I suspect regs_to_read is global).

You could try assigning regs_to_read in a function called before anything else uses that array.

like image 111
cnicutar Avatar answered Sep 19 '22 12:09

cnicutar


const doesn't make them constants at compile time. Make them #defines and the compiler will be happy.

like image 30
ddyer Avatar answered Sep 17 '22 12:09

ddyer


I think this may be a compiler issue, and it would be helpful to know your platform and how you are building this code. I just took most of your code, doctored it up to compile it, and compiled on Linux using gcc. There were no warnings.

#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);
}

Have you tried casting the values? It's not always the best thing to do, but will get you around the error.

Have you considered creating #define entries?

Also, please be aware consts take a bit of getting used to in C. They do not always behave the way you might expect.

like image 28
octopusgrabbus Avatar answered Sep 19 '22 12:09

octopusgrabbus