cgcc-warning

"Variably modified" warning with #defined sizes


The following C snippet, when compiled with ARM GCC 13.2.1 (Godbolt link):

#include <stdint.h>

#define LEDLINE_LED_COUNT     5

// LED delay buffer parameters; adjust the first two if you change filter parameters.
#define DELAY_MOTION_FILTER   115     // ms delay of motion filter, measured
#define DELAY_LED_FILTER      0       // ms delay of led filter, TODO
#define LED_DELAY_INTERVAL    10      // ms per frame for led delay processing
#define LED_DELAY_TIME        (DELAY_MOTION_FILTER - DELAY_LED_FILTER)
#define LED_DELAY_FRAMES      ((int)((float)LED_DELAY_TIME / (float)LED_DELAY_INTERVAL + 0.5))

static uint16_t g_ledDelayBuffer[LEDLINE_LED_COUNT][LED_DELAY_FRAMES] = {0};

Yields the variably modified at file scope warning, which according to that post comes from using non-constant sizes in array declarations.

But, I don't really understand why the above generates that warning; I guess I assumed the compiler calculated the value of LED_DELAY_FRAMES when compiling the code and reduced it to a constant, but it seems like that's not true?

What is it about that #define that makes it not usable here and is there some other way to do what I'm trying to do here (without dynamically allocating memory)?

The main reason I have LED_DELAY_FRAMES declared the way it is is because I want it to be semantically clear how all those parameters are related and I also want to make it have the correct value based on the first 3 parameters, which are tune-able. The floats and + 0.5 are there to round the result.


Solution

  • To qualify as a constant length (rather than a variable length), the array size must be an integer constant expression, per C 2024 6.7.7.3. The C standard does not require implementations to do floating-point calculations in integer constant expressions. C 2024 6.6 says:

    An integer constant expression shall have integer type and shall only have operands that are integer constants, named and compound literal constants of integer type, character constants, sizeof expressions whose results are integer constants, alignof expressions, and floating, named, or compound literal constants of arithmetic type that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the typeof operators, sizeof operator, or alignof operator.

    Note 0.5 is a floating constant that is not the immediate operand of a cast, (float) is a cast that does not convert to an integer type, and the operands of the / would be float values.

    Assuming the values are not large enough to cause overflow, you can replace ((int)((float)LED_DELAY_TIME / (float)LED_DELAY_INTERVAL + 0.5)) with ((LED_DELAY_TIME + LED_DELAY_INTERVAL/2) / LED_DELAY_INTERVAL).