Why I cant declare a constant in a function? - c

I am getting this error when I try to execute the following function
src\main.c(41): error: #259: constant value is not known
The code:
uint8_t checksum_tx(uint64_t Data, uint8_t dataLength, uint8_t checksum_len ) {
const uint8_t length = (dataLength + checksum_len - 1) / checksum_len;
//** splitting data into 6-bits subunits . . .
uint8_t res = 0U;
uint8_t dataSubUnit[length];
the line that causes the error
const uint8_t length = (dataLength + checksum_len - 1) / checksum_len;
could someone clarify what is going wrong?
I read somewhere the constants in C must be declared directly, it is not allowed to initialize them, I guess that is what I have done.

This is a limitation of the language... or a feature (depends on who reads it) for the const tagged object. I think your interpretation of the const keyword, applying to a data object with a limited life, should make it immutable for the life of the object, this is, the execution of the block in which it is defined. But the compiler makes the data effectively a constant (like the constant PI) and it must hold the same value for the whole program life, and not on each function invocation. In the case you post, the value of the expression that the constant will have is not known until the function is started and the parameters receive their values (only then can the initialization expression be evalutated), so the constant is not actually a constant (You could provide different values for the function parameters in different call and make the constant value different than in the previous call).
In java, for example, there's a final keyword to mark a data value as constant, and you must preserve (you are not allowed to assign/change values to it) during the life of the object (this meaning since it is created until it is destroyed), but the initial value is determined dynamically, at the time of creation. This is not true in C. A const declared data object must be actually a constant, and it must be initialized by an expression (called a const expression) whose value can be determined at compilation time.

Constants are not real variables: once the code is compiled constants are translated into hard-coded values (immediate operands), or references within a section of the program that cannot be written (usually .rodata).
So, constants can't be assigned a value at run-time. You have to set a value that is known at compilation time, hence a value that does not depend on other variable(s). (e.g. const int length = 42; ).
If you cannot know the value of length before compiling the code, then you need a variable, not a const.
I guess you needed a constant to declare the array dataSubUnit. The usual way to solve this is to declare an array large enough to contain any possible length:
#define MAX_DATA_SUBUNIT_LEN 42
uint8_t checksum_tx(uint64_t Data, ... ) {
uint8_t dataSubUnit[MAX_DATA_SUBUNIT_LEN];
... and to prevent a possible overflow:
uint8_t length = (dataLength + checksum_len - 1) / checksum_len;
if ( length < MAX_DATA_SUBUNIT_LEN ) {
... // proceed
}
else {
// return some relevant error code
}

Related

How to use const pointers inside structures?

hope everyone is doing great!
I was trying to implement some lib in embbeded enviroment, where i need to use const pointers.
Here is the code i was trying to do:
#include <stdio.h>
int a = 10;
typedef struct {
void * const payload;
int size;
} msg;
typedef struct {
void * const payload2encode;
int size2encode;
} encode_msg;
msg message[1] = {
{
/* payload */ &a,
0
}
};
encode_msg encoded_message = {
/* payload */ message[0].payload,
0
};
int main(void){
return 0;
}
but i'm getting the following error:
main.c:23:19: error: initializer element is not constant 23 |
/* payload */ message[0].payload,
If I change 'message[0].payload' to '&a' the code runs fine. I don't get why this is happening :(. Anyone know why?
Best reggards!
There are a lot of misconceptions here.
First of all, why do you need a "constant pointer"? This message here:
error: initializer element is not constant
Does not mean "the compiler wants a constant pointer", but rather "I want a a compile-time constant such as an integer constant expression". This has nothing to do with const at all in C (C++ is another story), but this:
A variable with static storage duration, like one declared at file scope outside any function, must be initialized with a constant expression. Such as an integer constant expression or in case of pointers the address of another variable. But it cannot be initialized to the value of a different variable. Simple example:
int a = 0;
int b = a; // error: initializer element is not constant
That's just how the language works. You could initialize a pointer to an address however, since address constants are constant expressions. That's why /* payload */ &a, works.
Next misconception: there is nothing called "constant pointer". There are:
pointers to read-only data, const type* name.
read-only pointers to read/write data: type* const name.
read-only pointers to read-only data: const type* const name.
For some reason you picked the second of these options (took a gamble?). It has limited uses, but one valid use of it is to declare read-only pointer variables in ROM on embedded systems with true ROM like flash.
Also we usually don't want to use qualifiers like const inside a struct on an individual member if we can avoid it. Because then the struct variable itself ends up with different qualifiers than it's members. Normally we want the whole struct to be const or nothing in the struct at all. In embedded systems we also need to consider if we want it to be stored in RAM or flash.
Regarding void*, they are not very suitable to use for any purpose in an embedded system. uint8_t* boiling down to a character pointer is much more useful, since it can be used to access any other type byte by byte. Whereas a void* has to be converted to another type before we can do anything meaningful with it. Type-generic programming in embedded systems is also a bad idea most of the time, since such systems should behave deterministically.
encoded_message has static storage duration (because it's declared outside any function) and so must be initialized with a constant expression, and message[0].payload isn't (it's a const variable, but not a constant expression).
You can either declare encoded_message in a function (main, for instance), or, if your compiler supports it, make message const as well.
See also : Error "initializer element is not constant" when trying to initialize variable with const

initializer element not constant?

I am relatively knew to C and only learning pieces of it to publish a Pebble C/PebbleKitJS app to track buses. So far I have the data being processed on a Node server, and I am getting ready to have the data processed by a JS File. MY one problem however lies within the C Code.
This code process data stored in a Key Dictionary sent from JS and assigns it to a variable for use below. By using #define var 9, I can successfully have the .high value set to 9. But through an int var, it fails and throws the error:initializer element not constant?? .
What does this error mean, and what exactly is the difference between static and constant if i don't define it. apparently static vars don't return anything? Some help would be much appreciated.
UPDATE: The problem still isn't fixed. The following new error message occurs in addition to the initializer one. error: (near initialization for 's_data_points[0].high')
int key0_buffer;
void process_tuple(Tuple *t)
{
//Get key
int key = t->key;
//Get integer value, if present
int value = t->value->int32;
//Get string value, if present
char string_value[32];
strcpy(string_value, t->value->cstring);
//Decide what to do
switch(key) {
case key_0:
//Location received
key0_buffer = value;
break;
}
}
static WeatherAppDataPoint s_data_points[] = {
{
.city = "San Diego",
.description = "surfboard :)",
.icon = WEATHER_APP_ICON_GENERIC_WEATHER,
.current = 110,
.high = key0_buffer,
.low = 9,
},
};
Try this instead:
enum { key0_buffer = 9 };
C doesn't provide for runtime computations while initializing global variables. (The concept does exist as a C++ feature called "dynamic initialization.")
The execution model is that it can store all the bytes of global variables in ROM, and then copy any modifiable variables into RAM together with a single memcpy. Assigning one global to another would be more complicated.
#define allows you to substitute the text 9, which is a constant expression.
Many frown upon using text substitutions to avoid variables as primitive, unnecessarily low-level, and potentially inefficient. In this case though, the results should be the same.
In C, enum constants have type int, so they are a suitable substitute. You're out of luck for other types, though.
There is a key difference between the code in your function and the code lower down that defines the static variable. The function code is executable -- these lines are going to get run when the function is called.
Your static declaration of WeatherAppDataPoint is just telling the compiler to create the static variable. The initialization values you are placing in that declaration tell the compiler what value to initialize this data to. That is why they must be constant -- these are the values that get loaded in before anything gets executed.
The #define statement just tells the preprocessor to replace all instances of "var" with the string "9". It is literally the same as a cut and paste operation in a text editor. This gets done before the compiler ever sees the code. This is why you have no problems with that; the compiler sees a literal constant, just as if you'd manually typed the "9" directly into the source code.
In 'C', variables don't return things, they store them. Only functions return things. If you want to have an integer declared somewhere, and then assign it to the value of your static variable, that is an actual executable line of code that will need to occur inside of a function somewhere (ie inside of your process_tuple function). The lines of code below the static declaration aren't executed at run time, they just setup the initial state of the program and tell the compiler how big the variable is.

c warning: use of const variable in a constant expression is non-standard in C

I'm getting this warning when trying to initialize an array to a constant size.
#2170-D use of a const variable in a constant expression is nonstandard in C
#file.h
typedef struct {
// LED Blink Pattern
.....
} LEDSeq
void addError(LEDSeq);
void runLEDErrors();
....
#file.c
const uint8_t MAXERRORS = 4;
LEDSeq errors[MAXERRORS];
uint8_t errorsLength = 0;
....
Essentially it's a bit of code that is going to loop over LED error sequences that are added during run time. I've got to use a fixed size array because realloc isn't available in my environment. The code all works. I'm just wondering why I'm getting this error.
A const object is not a constant in C but a read-only object. An array declared at file scope (or any array with static storage duration) has to have a constant expression as its number of elements.
This is valid:
#define MAXERRORS 4
LEDSeq errors[MAXERRORS];

How enum constants are processed

How enum constants are processed in a C program. I know these constants are not stored in memory.
So I wonder how during execution our program refers any enum constant.
enum data
{
first_value = 100,
second_value = 200
};
enum data value;
During execution how "first_value" or "second_value" is referred if they are not in memory?
As they cannot change value ever, they are just replaced with their number. In the same way that in the expression
i += 1;
the 1 isn't necessarily stored anywhere (you cannot take its address) the enum values aren't stored anywhere. They might be mixed in with the code, they might be optimised out, they may even be made part of an increment instruction.

Declare a constant array

I have tried:
const ascii = "abcdefghijklmnopqrstuvwxyz"
const letter_goodness []float32 = { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }
const letter_goodness = { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }
const letter_goodness = []float32 { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }
The first declaration and initialization works fine, but the second, third and fourth don't work.
How can I declare and initialize a const array of floats?
An array isn't immutable by nature; you can't make it constant.
The nearest you can get is:
var letter_goodness = [...]float32 {.0817, .0149, .0278, .0425, .1270, .0223, .0202, .0609, .0697, .0015, .0077, .0402, .0241, .0675, .0751, .0193, .0009, .0599, .0633, .0906, .0276, .0098, .0236, .0015, .0197, .0007 }
Note the [...] instead of []: it ensures you get a (fixed size) array instead of a slice. So the values aren't fixed but the size is.
As pointed out by #jimt, the [...]T syntax is sugar for [123]T. It creates a fixed size array, but lets the compiler figure out how many elements are in it.
From Effective Go:
Constants in Go are just that—constant. They are created at compile time, even when defined as locals in functions, and can only be numbers, characters (runes), strings or booleans. Because of the compile-time restriction, the expressions that define them must be constant expressions, evaluatable by the compiler. For instance, 1<<3 is a constant expression, while math.Sin(math.Pi/4) is not because the function call to math.Sin needs to happen at run time.
Slices and arrays are always evaluated during runtime:
var TestSlice = []float32 {.03, .02}
var TestArray = [2]float32 {.03, .02}
var TestArray2 = [...]float32 {.03, .02}
[...] tells the compiler to figure out the length of the array itself. Slices wrap arrays and are easier to work with in most cases. Instead of using constants, just make the variables unaccessible to other packages by using a lower case first letter:
var ThisIsPublic = [2]float32 {.03, .02}
var thisIsPrivate = [2]float32 {.03, .02}
thisIsPrivate is available only in the package it is defined. If you need read access from outside, you can write a simple getter function (see Getters in golang).
There is no such thing as array constant in Go.
Quoting from the Go Language Specification: Constants:
There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants. Rune, integer, floating-point, and complex constants are collectively called numeric constants.
A Constant expression (which is used to initialize a constant) may contain only constant operands and are evaluated at compile time.
The specification lists the different types of constants. Note that you can create and initialize constants with constant expressions of types having one of the allowed types as the underlying type. For example this is valid:
func main() {
type Myint int
const i1 Myint = 1
const i2 = Myint(2)
fmt.Printf("%T %v\n", i1, i1)
fmt.Printf("%T %v\n", i2, i2)
}
Output (try it on the Go Playground):
main.Myint 1
main.Myint 2
If you need an array, it can only be a variable, but not a constant.
I recommend this great blog article about constants: Constants
As others have mentioned, there is no official Go construct for this. The closest I can imagine would be a function that returns a slice. In this way, you can guarantee that no one will manipulate the elements of the original slice (as it is "hard-coded" into the array).
I have shortened your slice to make it...shorter...:
func GetLetterGoodness() []float32 {
return []float32 { .0817,.0149,.0278,.0425,.1270,.0223 }
}
In addition to #Paul's answer above, you can also do the following if you only need access to individual elements of the array (i.e. if you don't need to iterate on the array, get its length, or create slices out of it).
Instead of
var myArray [...]string{ /* ... */ }
you can do
func myConstArray(n int) string {
return [...]string{ /* ... */ }[n]
}
and then instead of extracting elements as
str := myArray[i]
you extract them as
str := myConstArray(i)
Link on Godbolt: https://godbolt.org/z/8hz7E45eW (note how in the assembly of main no copy of the array is done, and how the compiler is able to even extract the corresponding element if n is known at compile time - something that is not possible with normal non-const arrays).
If instead, you need to iterate on the array or create slices out of it, #Paul's answer is still the way to go¹ (even though it will likely have a significant runtime impact, as a copy of the array needs to be created every time the function is called).
This is unfortunately the closest thing to const arrays we can get until https://github.com/golang/go/issues/6386 is solved.
¹ Technically speaking you can also do it with the const array as described in my answer, but it's quite ugly and definitely not very efficient at runtime: https://go.dev/play/p/rQEWQhufGyK

Resources