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.
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.
lowercase 213 / 202 / 85 Регистрация: 09.05.2012 Сообщений: 494 |
||||||||||||
1 |
||||||||||||
23.09.2013, 18:40. Показов 12907. Ответов 36 Метки нет (Все метки)
Здравствуйте. Наткнулся(ладно, каюсь — сам написал) на вот такой код:
он не компилируется в связи с тем что:
я несколько непонимаю почему так? ведь x — константа, а 1.0 разделить на константу — тоже константа. то есть, я какбы константу инициализирую константой, однако gcc имеет инное мнение по этому поводу. полагаю дело в static, т.к. если убрать спецификатор const, то ошибка остается. а вот так работает:
гугление выдает только информацию, касательно того как static, действует на область видимости переменной.
0 |
castaway 4982 / 3089 / 456 Регистрация: 10.11.2010 Сообщений: 11,165 Записей в блоге: 10 |
||||
23.09.2013, 18:47 |
2 |
|||
Мой GCC 4.7.3 жуёт без предупреждений и ошибок с флагом -pedantic
0 |
213 / 202 / 85 Регистрация: 09.05.2012 Сообщений: 494 |
|
23.09.2013, 18:48 [ТС] |
3 |
я конечно обошелся и без статичности, сделав #define, однако интересно узнать почему static const не срабатывает
0 |
4982 / 3089 / 456 Регистрация: 10.11.2010 Сообщений: 11,165 Записей в блоге: 10 |
|
23.09.2013, 18:55 |
4 |
Тьфу блин… это ж Си..
0 |
213 / 202 / 85 Регистрация: 09.05.2012 Сообщений: 494 |
|
23.09.2013, 18:56 [ТС] |
5 |
результат на
консоль: Миниатюры
0 |
Z3JheSBoYXQ= 342 / 237 / 83 Регистрация: 08.07.2012 Сообщений: 577 |
|
23.09.2013, 20:42 |
6 |
Потому что static дает указание компилятору резервировать сегмент памяти в течении процесса выполнения программы под переменную. Мкроподстановки к таковым не относятся.
1 |
213 / 202 / 85 Регистрация: 09.05.2012 Сообщений: 494 |
|
23.09.2013, 20:46 [ТС] |
7 |
fanatdebian, не совсем понятно. ининциализация static-переменных происходит на этапе выполнения, я правильно понял?
0 |
Z3JheSBoYXQ= 342 / 237 / 83 Регистрация: 08.07.2012 Сообщений: 577 |
|
23.09.2013, 20:49 |
8 |
fanatdebian, таким образом инициализация static переменных происходит на этапе выполнения, я правильно понял? ofc.
1 |
213 / 202 / 85 Регистрация: 09.05.2012 Сообщений: 494 |
|
23.09.2013, 20:53 [ТС] |
9 |
чудненько. спасибо
0 |
4982 / 3089 / 456 Регистрация: 10.11.2010 Сообщений: 11,165 Записей в блоге: 10 |
|
23.09.2013, 20:56 |
10 |
Да ну при чем тут static .. это всего-лишь издержки стандарта языка Си.
0 |
Z3JheSBoYXQ= 342 / 237 / 83 Регистрация: 08.07.2012 Сообщений: 577 |
|
24.09.2013, 00:31 |
11 |
Да ну при чем тут static .. это всего-лишь издержки стандарта языка Си. В чем издержки?. Все логично и правильно на самом деле. С какой стати компилятор должен для макроподстановок резервировать память. Это всего лишь конструкция-форма, определяющая короткую запись для обработки конкретных данных размещенных в памяти.
0 |
4982 / 3089 / 456 Регистрация: 10.11.2010 Сообщений: 11,165 Записей в блоге: 10 |
|
24.09.2013, 00:36 |
12 |
С какой стати компилятор должен для макроподстановок резервировать память. Тут же нет макроопределений. Ты о чем?
0 |
fanatdebian Z3JheSBoYXQ= 342 / 237 / 83 Регистрация: 08.07.2012 Сообщений: 577 |
||||
24.09.2013, 08:59 |
13 |
|||
Тут же нет макроопределений. Ты о чем? Прямых нет, косвенные есть.
Такая конструкция у компилятора вызывает диссонанс по причине отсутствия в момент прохода выделенной памяти под y для завершения остаточной конструкции / (double)x; Не может лошадь везти телегу задом наперед.
0 |
Модератор 13245 / 10387 / 6210 Регистрация: 18.12.2011 Сообщений: 27,784 |
|
24.09.2013, 09:00 |
14 |
Некоторые рассуждения.
0 |
1259 / 650 / 44 Регистрация: 06.02.2011 Сообщений: 1,654 |
|
24.09.2013, 10:20 |
15 |
Константы (вещественные/целые числа и символы) и квалификатор типа (const/restrict/…) суть разные вещи.
0 |
21265 / 8281 / 637 Регистрация: 30.03.2009 Сообщений: 22,645 Записей в блоге: 30 |
|
24.09.2013, 10:26 |
16 |
я несколько непонимаю почему так? Проблема в том, что в правой части присваивания находится выражение плавающего типа. Любое плавающее выражение обладает побочными эффектами в виде изменения состояния плавающих статусных регистров процессора, которые при определённых установленных масках должны вызывать аппаратное прерывание. Другими словами, когда мы имеем динамическую инициализацию, то в процессе её вычисления может случиться прерывание и программа попадёт в обработчик прерываний. В случае статической инициализации такое сделать невозможно: компилятор не знает, взведены ли биты, отвечающие за прерывания, не знает, есть ли вообще обработчик прерывания. И может получиться так, что программа со статической и динамической инициализацией будет вести себя по разному. Поэтому запретили плавающие выражения в качестве статических инициализаторов
0 |
1259 / 650 / 44 Регистрация: 06.02.2011 Сообщений: 1,654 |
|
24.09.2013, 10:48 |
17 |
Проблема в том, что в правой части присваивания находится выражение плавающего типа Вы о чем? как на счет int a = 1; int b = a + 1; ???
0 |
fanatdebian Z3JheSBoYXQ= 342 / 237 / 83 Регистрация: 08.07.2012 Сообщений: 577 |
||||
24.09.2013, 11:24 |
18 |
|||
Вы о чем? как на счет int a = 1; int b = a + 1; ??? Тут линейное присваивание. Сложностей для компилятора не видать.
память выделена и и известны значения по этим сегментам памяти, поэтому такое присваивание и происходит без проблем.
0 |
1259 / 650 / 44 Регистрация: 06.02.2011 Сообщений: 1,654 |
|
24.09.2013, 11:38 |
19 |
Тут линейное присваивание. Забавно. Какой-то новый стандарт языка вышел? Можно ссылку на определение термина «линейное присваивание»? Причем тут память?
поэтому такое присваивание и происходит без проблем. покажите где такое сработает?
0 |
21265 / 8281 / 637 Регистрация: 30.03.2009 Сообщений: 22,645 Записей в блоге: 30 |
|
24.09.2013, 12:34 |
20 |
Проблема в том, что в правой части присваивания находится выражение плавающего типа. Любое плавающее выражение обладает побочными эффектами в виде изменения состояния плавающих статусных регистров процессора, которые при определённых установленных масках должны вызывать аппаратное прерывание. Другими словами, когда мы имеем динамическую инициализацию, то в процессе её вычисления может случиться прерывание и программа попадёт в обработчик прерываний. В случае статической инициализации такое сделать невозможно: компилятор не знает, взведены ли биты, отвечающие за прерывания, не знает, есть ли вообще обработчик прерывания. И может получиться так, что программа со статической и динамической инициализацией будет вести себя по разному. Поэтому запретили плавающие выражения в качестве статических инициализаторов Чота я по ходу глупость сморозил, в очередной раз невнимательно посмотрев на тест. Тут речь вообще шла о языке Си. В языке Си в качестве инициализатора может быть только константное выражение. В исходном примере в правой части использовалась переменная, а потому с точки зрения языка Си выражение не является константным (хотя в Си++ такое допустимо и будет работать). Правда в printf’е нужно использовать %f, а не %lf, но это мелочи. Сейчас попытаюсь сообразить, к каким же случаям применяется то, чего я понаписал Добавлено через 7 минут
Сейчас попытаюсь сообразить, к каким же случаям применяется то, чего я понаписал Из всего того, что пришло в голову, ничего под это не попадает. По ходу дела я что-то с чем-то спутал. Каюсь
1 |
1. First, solve the problem of error reporting as shown in the title;
Take a look at the following code:
#include <stdio.h>
int a = 1;
int b = 2;
int c = a+b;
int main() {
printf("c is %dn", c);
return 0;
}
Error during compilation of GCC-O test test.c: Initializer Element is not Constant
Reason: the value of the global variable C cannot be determined at compile time; it must be determined at run time. Why is that?Because this is the standard:
C language standard: Initializers of external variables and static variables must be constant expressions [1].
So the solution:
#include <stdio.h>
int a = 1;
int b = 2;
int c;
int main() {
c = a + b;
printf("c is %dn", c);
return 0;
}
———-
Similarly, the following code does not compile, and the error message is the same as above: [4]
char * p1 = (char *) malloc(10);
int main(void)
{
。。。
}
2. Do GCC and g++ compile according to the suffix name of the file?
If you change the source file name *.c to *.cc, and then compile with g++, no error will be reported. Even if you just change the file name to *.cc, the compiler will also compile with GCC, which can also compile the past. What is the reason?
————–
Principle:
GCC started out as GNU C Compiler, which is, as you know, a C Compiler. But later, as the project integrated more compilers in different languages, GCC stood for the GNU Compiler Collection, thus representing a Collection of compilers.
So instead of calling GCC when you compile your code, it’s more like a driver that calls the c compiler or the c++ compiler (g++) based on the suffix of your code. For example, if your code suffix is *.c, it will call the C compiler and linker to link to C’s library. If your code suffix is CPP, it will call the g++ compiler, and of course the library call will also use the c++ version (however, the GCC command does not automatically link to the library used by c++ programs, you must follow the parameter gcc-lstdc ++)
—————–
Here’s a piece of code:
#include <iostream>
using namespace std;
int a = 1;
int b = a;
int main()
{
cout << b << endl;
}
The Initializer Element is not constant because GCC identifies the code as C, and C specifies that initializing global variables must be a constant expression.
If $GCC test.cc, undefined reference to ‘STD ::cout’… Wait… Error: ld returned 1 exit status. Although GCC recognized c++ code at this time, it would not automatically link c++ code base, so ld link error appeared. At this point only need to manually specify and C ++ library link C: $GCC test.cc-LSTDC ++, at this point you can smoothly through the compilation link.
———————
G++ is the c++ compiler for GCC. At compile time, g++ calls GCC, so for c++ code, the two are equivalent. But since the GCC command does not automatically associate with the library used by c++ programs, it is common to use g++ for linking, so for the sake of uniformity, compile/link all use g++, giving the illusion that c++ programs can only use g++.
So you can understand it this way: you can compile with GCC /g++, and you can link with either g++ or gcc-lstdc ++. Because GCC commands do not automatically join with libraries used by C++ programs, g++ is usually used to complete the join. But at compile time, g++ automatically calls GCC, which is equivalent.
For the above code, just $g++ test.c will compile because g++ identifies *.c files as c++ files [2].
The compiler is through the program suffix name to determine the language is C or C ++. Specifically, if the suffix is.c, GCC treats it like a c program, and g++ treats it like a c++ program; CPP suffix, both are considered as c++ programs, note that although c++ is a superset of c, but the syntax requirements of the two are different [2], for c language and c++ language suffix name problem, see [7]
(3) for 1 is the C language standard, not C++, for C++, global variables and static variables do not have to follow the initialization must be constant expression such requirements, so, if the compiler to identify the above code into C++ code, then it can be successfully compiled in the past. (And the program USES the same libraries as the C language, so it’s ok not to add -LSTDC ++ parameter.
Therefore, since the suffix name of the file is changed to *.cc, I guess that whether GCC or g++, this file is identified as c++ file, so it is clear that since it is identified as c++ file, of course not to report an error.
3, compiler strong and weak symbols
In C, global variables default to 0 if they are not initialized, that is, in the global space:
int x =0; With the int x; The effect looks the same. The difference is very big, but here it is strongly recommended that you all global variables
to initialization, the main difference between them is as follows:
the compiler when compiling for both conditions can produce two kind of symbols in the symbol table of the target file, for initialization, called
symbol, an uninitialized, called weak symbols.
if the connector encounters two duplicate symbols while connecting to the target file, it will have the following processing rule:
if there are strong symbols with multiple duplicate names, it will report an error.
if there is a strong symbol and more than one weak symbol, the strong symbol shall prevail.
if there is no strong symbol, but there are more than one weak symbol with the same name, then choose any weak symbol.
————-
So here’s a piece of code:
#include<stdio.h>
int i;
i =1;
int main()
{
printf("%dn", i);
}
GCC test. C
Can be compiled, but with warning: Data Definition has no type or Storage class
What does that mean?I =1, the definition of an I variable has no type;
So the code looks like this:
#include<stdio.h>
#include<stdlib.h>
int i;
j=1;
int main()
{
printf( "%dn", j);
printf( "%dn", i);
system( "pause" );
return 0;
}
gcc test.c
This code also has warning; data definition has no type or storage class
So for I =1; The compiler takes it as the definition + initialization of a variable.
and the int I before; Because I is equal to 1; So int I is weak, it doesn’t work; [3]
However, the above two pieces of code, if using g++ compiler, that is, according to the rules of c++ compiler, will be directly error:
“J does not name a type” because c++ is a mandatory language, can not be so casual!
It is worth noting that the first paragraph of the above two code also reports an error in g++ : “I does not name a type”. It is understandable that j compilation should not pass, because j is not defined at all. Int I = 1; int I = 1; Int j = 2; int c = a+b; G++ is passable. What’s the problem?See section 4 of this article.
————–
Here’s another piece of code:
#include <stdio.h>
struct stu
{
long number;
};
struct stu student;
student.number = 1;
int main(int argc, char * argv[])
{
printf("%dn", student.number);
}
Why is that?
The assignment statement should be placed in the function body!
Initialization can be outside the body of the function… But the assignment must be inside the body of the function…
Moreover, not only are structures assigned, but most statements (other than declarations and definitions of functions and variables) do not allow…
So understand the difference between initialization and assignment;
(This applies to C and C ++)
**** It should also be noted that in C language, struct is required when defining structural variables, while in C ++, it is not required. Stu Student = {1}; You can, but with struct you can compile it, you can run it.
4. Why is it specified that the initial values of global and static variables must be constant expressions?
Now that we’ve solved the problem, and we’ve analyzed why we did it, we can go deeper. Why do global variables and static variables have to be initialized as constant expressions?
Global (static) storage: Divided into DATA segments and BSS segments. The DATA section (global initialization section) holds initialized global and static variables; The BSS section (global uninitialized area) holds uninitialized global and static variables as well as initialized to zero global and static variables (see here). Automatic release at the end of the program. The BBS section is automatically cleared by the system before the program execution, so uninitialized global variables and static variables are already 0 before the program execution. – The program is released by the system after completion. [5]
——-
A comparison, for the statement:
int i = 3
int main()
{
int j = i;
...
}
Instead of determining the value of the local variable J at compile time, the value of I is read at run time to assign to J. The compiled connected executable does not contain the value of J, only the code for the corresponding assignment statement. In contrast, since I is a global variable and is stored in static storage, its value needs to be determined at compile time. Space will be allocated in the target file to store the value of I. There will be no assignment statement to assign the value of I at run time, and there is no corresponding code.
for the statement:
int i = 3;
int j = i;
Because J is a global variable and is stored in static storage, its value also needs to be determined at compile time. I is a variable, not a constant, and the value of I cannot be determined at compile time, which means that the value of J cannot be determined at compile time, so C will report an error.
Instead, C++ simply puts j as an uninitialized global variable in the.bss area at compile time, with the default value of 0, and then adds a statement to assign j at run time, ensuring that this statement is executed before the main function begins. So the initialization of j is actually done at run time. [6]
So, we can now answer the question raised in red in section 3:
1. For int I = 1; int j = 2; int c = a+b; This sentence, in g + + through because the statement is the c at compile time as a variable declaration, because the front of the variable c has keyword int, then the compiler will be additional add a statement c = a + b, and ensure that the statement before the main function, g + + this way to make this statement to the right by compiling.
2. For int I; I = 1; G++ does not compile. The reason is that an assignment statement like I = 1, which is different from an int c = a+b, requires a value at run time; I =1 cannot be regarded as a declaration of a variable (I variable has no type in front of it),,,,,,, etc
Tip: GCC compiler plus the -v parameter, displays compile-time details, compiler version, compilation process, etc.
Read More:
As a developer, you may have come across the «Initializer element is not constant» error while coding. This error message indicates that there is a problem with the initialization of a variable in your code. In this guide, we will explore the possible causes of this error and provide a step-by-step solution to fix it.
What Causes the «Initializer Element is Not Constant» Error?
This error is usually caused by attempting to initialize a variable with a non-constant value. In C, for instance, you can only initialize a variable with a constant value at compile-time. If you try to initialize a variable with a non-constant value, you will get the «Initializer element is not constant» error.
How to Fix the «Initializer Element is Not Constant» Error
To fix this error, you need to ensure that you only initialize variables with constant values. Here are the steps to follow:
Check the declaration of the variable that is causing the error. Look for an initialization that may be causing the problem.
If you find an initialization, ensure that it is a constant value. A constant value is a value that does not change throughout the execution of the program. For instance, in C, a constant value can be defined using the const
keyword.
If the initialization is not a constant value, remove it and assign a constant value to the variable later in the code.
- Re-compile your code and test it to ensure that the error is fixed.
Frequently Asked Questions
What is a constant value in programming?
A constant value is a value that does not change throughout the execution of the program. In C, you can define a constant value using the const
keyword.
Can I initialize a variable with a non-constant value?
No, in most programming languages, you can only initialize a variable with a constant value. Attempting to initialize a variable with a non-constant value will result in an error.
What other errors can cause problems with variable initialization?
Other errors that can cause problems with variable initialization include typos in variable names, incorrect syntax, and using the wrong data type.
How do I know which variable is causing the error?
The error message should provide you with the name of the variable that is causing the error. Look for the variable name in your code and check the initialization.
Can I use a variable as a constant value?
Yes, you can use a variable as a constant value if you declare it as such. In C, you can use the const
keyword to declare a variable as a constant.
- Understanding Variables and Constant Values in C Programming
- Common Syntax Errors in C Programming
Sometimes during complex programing, there are chances we make some mistakes during hurry to write and complete the program so that we can test the features, in somewhat similar occasion, we faced an error during compilation as, “error: initializer element is not constant” , now as mentioned, if we have written multiple lines during coding and before compilation, it becomes difficult to remember we initialized which variable and where..?
So, lets recreate similar error, with a very basic C program as below,
$ vim helloerror.c
#include <stdio.h>
#include <stdlib.h>
int *var = (int *)malloc(sizeof(int));
int main(int argc, char **argv) {
*var = 10;
printf("var is %dn", *var);
return 0;
}
$ gcc -o helloerror helloerror.c
$ ./helloerror
helloerror.c:4:12: error: initializer element is not constant
int *var = (int *)malloc(sizeof(int));
^
so, we got the mentioned error and during compilation, if the compiler is latest, it also shown the line of error.
Now, if we relooked at the code, we have a global integer pointer “var” and we are assigning a memory to it by calling malloc, ideally this looks OK, but the catch is this is a “GLOBAL” variable, outside all the functions, so the program execution only initialises these variables once, so these are expected to be constants and not changing like we have done an assigned of it to memory returned by malloc.
SO, to avoid this error, always make sure all global variables are assigned with constants.
Now, lets rewrite this program to make sure error is gone,
#include <stdio.h>
#include <stdlib.h>
int *var = NULL;
int main(int argc, char **argv) {
var = (int *)malloc(sizeof(int));
*var = 10;
printf("var is %dn", *var);
return 0;
}
Changes are done in “int *var = NULL;” and moving malloc statement inside main.
Programming has become a lot easier these days thanks to the numerous resources available on the internet. That said, there are still hoops that every developer needs to jump through in order to get their code to run. Random bugs and glitches are still very much an everyday thing for most if not all programmers.
In this article, we’re talking about the “error: initializer element is not constant” issue, its causes and what you can do to fix the problem.
What causes this error?
There are actually a number of reasons why you’d see this error. However, the main reason why this happens is that you’ve declared the element outside of the main or any other functions using it, implicitly stating that the variable has a static storage location. This means that the initialised variable is now global. In C, there’s a rule stating that global variables need to be initialised with constant expressions, which is the point of error here.
Also read: What is regsvr32 kernelbase.dll? Quick Fix for crashes
How to fix this?
The fix is relatively simple. You can either:
- Declare a global variable with a constant value (or expression)
- Declare and use a local variable for the main or a specific function.
Depending on your code and what you’re trying to do, you might want to shy away from global variables here. Unless you’re comparing two or more values or have an explicit need for a global variable, it’s best to declare and use local variables for any specific methods that you might have written and will use when the program executes.
Alternatively, you might want to simply declare a global variable with a constant value or expression. For example:
// Here's how you declare global varaibles
#include <stdio.h>
int x = 1; // global variable
int main() {
int y = 2; // local variable
return 0;
}
The snippet mentioned above declares a global variable, x, which has a constant value of five. Hence you can use this variable anywhere in your code without triggering any errors. If you’re using an expression to declare the variable, make sure that the expression is valid and has all the inputs it needs.
Also read: No bootable devices found: Quick Fix