cannot appear in a constant-expression - c++

In the following c++ program:
static const int row = (dynamic_cast<int>(log(BHR_LEN*G_PHT_COUNT)/log(2)));
static const int pht_bits = ((32*1024)/(G_PHT_COUNT * G_PHT_COUNT * BHR_LEN));
unsigned char tab[pht_bits][1<<row];
I get the error message double log(double)’ cannot appear in a constant-expression.
why am I getting this problem since i have put an integer cast in front? How should i fix this?

The constant-expression that the compiler is referring to is actually the bounds of the array tab. The dimensions of statically allocated arrays have to be known at compile-time, but the value of row can't be determined until runtime, because it is evaluated using a function.

To you that are downvoting my answer. Tell me that this code does not work:
#include <stdio.h>
double log(double foo)
{
return 1.0;
}
static const int row = static_cast<int>(log(4)/log(2));
int main(void)
{
printf("%d\n", row);
return 0;
}
Original (changed from (int) to static_cast, not that it matters)
static const int row = static_cast<int>(log(BHR_LEN*G_PHT_COUNT)/log(2));

Related

Creating array with const int size parameter in a function throws error in Visual Studio C++: expression did not evaluate to a constant

void foo(const int size) {
char array[size];
}
int main() { }
The above code throws compiler error in Visual Studio C++:
error C2131: expression did not evaluate to a constant
note: failure was caused by a read of a variable outside its lifetime
Why is size not evaluated as constant even though it's declared as const int?
But the following code compiles successfully:
int main() {
const int size{ 10 };
char array[size];
}
This compiles because size is truly constant.
int main() {
const int size{ 10 };
char array[size];
}
This however will not compile, because size is a constant variable, and not a compile time constant (there's a subtle difference)
void foo(const int size) {
char array[size];
}
The reason it won't work, is because I can call foo with differing arguments.
foo(10);
foo(42);
foo(1);
The simplest work around is to use std::vector, which is what you are trying to do...
void foo(const int size) {
std::vector<char> array(size);
}
and now 'array' will work with the same intent as your original code.
C++ is a statically typed language and char array[1] and char array[2] are different types so those types must be known at compile time.
E.g
void foo(const int size) {
char array[size];
}
int main() {
int x = std::rand() % 1000;
foo( x ); // Error
}
In this case, compiler cannot know the type of char array[size] at compile-time because the size is decided at run-time, so it is an error.
So as #Frodyne stated in comments, size of static arrays must be constant expression
The size of an array needs to be a compile time constant, not just run-time const.
Since the constant variable size is initialized to '10', the value of the size cannot be modified. The size of the array is fixed and it cannot be changed.
int size = 10; // the value of the size can be changed.

global array initialization with a variable element [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in g++/
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
int j;
for (j=0;j<10;j++)
{
static int i = initializer();
/*The variable i is only initialized to one*/
printf(" value of i = %d ", i);
i++;
}
return 0;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#include <stdio.h>
typedef struct foo_t {
int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
const foo_t *const f1 = &s_FooInit;
const foo_t *const f2 = s_pFooInit;
printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
return 0;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

Declaring arrays with const variables

I am trying to create a multidimensional array, however when I pass a const int value I can't compile. Error is "expression must have a constant value" for each dimension.
class Matrix {
public:
Matrix(int rowCount, int columnCount, int scalarInput) {
const int row_C = rowCount;
const int colum_C = columnCount;
const int scalar_C = scalarInput;
matrixCalculation(row_C, colum_C, scalar_C);
}
void matrixCalculation(const int i, const int j, const int s) {
int matrixArray[i][j]; // error here, i and j: "expression must have a constant value"
}
};
Thanks
Array dimensions must be compile-time constant, and const doesn't mean that.
A const object cannot change its value after initialisation, but its initialiser may be determined at runtime (e.g. const int x = rand()) so, in general, these objects are not valid candidates for array dimensions.
Introducing... constexpr.
If you plonk the keyword constexpr in front of the dimensions, you will be off to a good start. Your compiler will prevent you from breaking the contract of constexpr, and will consequently enable you to use your shiny new constexpr object as an array dimension.
Alas, in this example, you are breaking that contract already, since the inputs are non-constant. Tough cookies.
Use a vector instead.

Passing a constant reference into a function

I am trying to pass a constant integer into a function using pass by reference.
#include <iostream>
using namespace std;
int test(int& num);
// changes a constant variable
int main() {
int loopSize = 7;
const int SIZE = loopSize;
cout<<SIZE<<endl;
test(loopSize);
cout<<SIZE;
return 0;
}
int test(int& num){
num -= 2;
}
However, the output is never updated.
SIZE and loopSize are two different objects. Even though SIZE started its life with loopSize's value at the time, changing one won't change the other. SIZE is not a reference.
Indeed, since SIZE is a constant you could never reasonably expect it to change anyway!
Is it possible that you intended to write the following?
const int& SIZE = loopSize;
// ^
You are changing loopSize and printing SIZE, so obviously the value won't change. Also, SIZE is a const, it won't change anyway.

How to convert int to const int to assign array size on stack?

I am trying to allocate a fixed size on stack to an integer array
#include<iostream>
using namespace std;
int main(){
int n1 = 10;
const int N = const_cast<const int&>(n1);
//const int N = 10;
cout<<" N="<<N<<endl;
int foo[N];
return 0;
}
However, this gives an error on the last line where I am using N to define a fixed
error C2057: expected constant expression.
However, if I define N as const int N = 10, the code compiles just fine.
How should I typecast n1 to trat it as a const int?
I tried : const int N = const_cast<const int>(n1) but that gives error.
EDIT : I am using MS VC++ 2008 to compile this... with g++ it compiles fine.
How should I typecast n1 to treat it as a const int?
You cannot, not for this purpose.
The size of the array must be what is called an Integral Constant Expression (ICE). The value must be computable at compile-time. A const int (or other const-qualified integer-type object) can be used in an Integral Constant Expression only if it is itself initialized with an Integral Constant Expression.
A non-const object (like n1) cannot appear anywhere in an Integral Constant Expression.
Have you considered using std::vector<int>?
[Note--The cast is entirely unnecessary. Both of the following are both exactly the same:
const int N = n1;
const int N = const_cast<const int&>(n1);
--End Note]
Only fixed-size arrays can be allocated that way. Either allocate memory dynamically (int* foo = new int[N];) and delete it when you're done, or (preferably) use std::vector<int> instead.
(Edit: GCC accepts that as an extension, but it's not part of the C++ standard.)