C - problem with const - error: initializer element is not constant - c

I try add global variable in my buttons.c file, but have a error - initializer element is not constant. Example headers.h file
struct MainStruct {
GtkEntryBuffer *buffer;
GtkWidget *entry;
GtkWidget *label;
};
extern struct MainStruct *p;
extern const char *text_entry;
void lower_button_clicked(GtkWidget *lowerbutton);
and when file main.c calls file buttons.c, I cannot define the variable text_entry. What am I doing wrong?
buttons.c
#include <gtk/gtk.h>
#include "headers.h"
const char *text_entry = gtk_entry_buffer_get_text(p -> buffer); // is not constant, why?
void lower_button_clicked(GtkWidget *lowerbutton)
{
printf("%s\n", text_entry);
}
I saw a lot of similar questions that talk about static, but
static const char *text_entry = gtk_entry_buffer_get_text(p -> buffer);
not working.
How do I define this variable to be global? to avoid duplication in similar functions

From the C Standard (6.7.9 Initialization)
4 All the expressions in an initializer for an object that has static
or thread storage duration shall be constant expressions or string
literals.
And in this declaration
const char *text_entry = gtk_entry_buffer_get_text(p -> buffer);
the initializer is not a constant expression. So the compiler issues an error.
Also pay attention to that these declarations
extern const char *text_entry;
and that follows it
static const char *text_entry = /*...*/;
contradict each other. The first declaration declares the variable text_entry as having external linkage while the second declaration declares the variable as having internal linkage.

Related

Best way to share multiple global variables between compilation units in C

I am trying to 'gather' global cmdOps spread in multiple files into lookup table for convenient usage in main. I did as shown below, but as pointed out this approach does not guarantee file1.c and file2.c to use the same variables, but I really want to avoid using extern declarations in file1.c as there will be tens of them if not more.
main.c:
#include "file1.h"
int getLutIdx(int argc, char *argv[]);
extern myLUT *LUT;
int main(int argc, char *argv[])
{
int idx = getLutIdx(argc, argv);
myArgs args;
LUT[idx].ops->parseArgs(argc, argv, &args);
LUT[idx].ops->validateArgs(&args);
LUT[idx].ops->executeCmd(&args);
}
file1.h:
typedef struct myArgs {
union {
cmd1Args_t cmd1Args;
cmd2Args_t cmd2Args;
...
}
}myArgs;
typedef int (*op1)(int argc, char *argv[], myArgs *args);
typedef int (*op2)(myArgs *args);
typedef int (*op3)(myArgs *args);
typedef struct cmdOps {
op1 parseArgs;
op2 validateArgs;
op3 executeCmd;
} cmdOps;
typedef struct myLUT {
char *cmdName;
cmdOps *ops;
}myLUT;
file1.c:
#include "file1.h"
#include "file2.h"
#include "file3.h"
myLUT LUT[CMD_NUM] {
{ "CMD1", &cmd1Ops },
{ "CMD2", &cmd2Ops },
...
}
file2.h:
int cmd1ParseArgs(int argc, char *argv[], myArgs *args);
int cmd1ValidateArgs(myArgs *args);
int cmd1Execute(myArgs *args);
int cmd2ParseArgs(int argc, char *argv[], myArgs *args);
int cmd2ValidateArgs(myArgs *args);
int cmd2Execute(myArgs *args);
cmdOps cmd1Ops;
cmdOps cmd2Ops;
file2.c
#include "file1.h"
#include "file2.h"
myOps cmd1Ops = {
.parseArgs= cmd1ParseArgs,
.validateArgs = cmd1ValidateArgs,
.executeCmd = cmd1Execute
}
myOps cmd2Ops = {
.parseArgs= cmd2ParseArgs,
.validateArgs = cmd2ValidateArgs,
.executeCmd = cmd2Execute
}
...
Whole question edited, thanks for previous comments.
Goal is for user to invoke:
./myProg <cmd_name> <cmd_args>
and each command (or sets of commands) can accept different parameters
The "best way" would be to not have any global variables (or at least, as few as possible), since global variables are likely to make your program difficult to understand and debug as it gets larger and more complex.
If you must have global variables, however, I suggest declaring the global variables in just one .c file:
myOps file2Ops; // in somefile.c
... and placing any necessary extern declarations in a .h file that other files can include:
extern myOps file2Ops; // in someheader.h
But it baffles me why don't I get any error or warning about duplicated declaration…
At file scope, myOps file2Ops; is a tentative definition, which is not actually a definition, directly. If there is no definition for it by the end of the translation unit, the behavior is as if there were a definition myOps file20ps = {0};. (Having an initializer would make the declaration a proper definition instead of a tentative definition.)
Then, because myOps file20ps; appears in file2.h and that is included in both file1.c and file2.c, your program has multiple external definitions of file20ps. The C standard does not define the behavior of this because it violates the constraint in C 2018 6.9 5:
… If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.
Historically, some C implementations have defined the behavior of external identifiers resulting from tentative definitions to act as “common” symbols. When linking the object modules, a definition originating from a tentative definition will be coalesced with other definitions, so there will be only one definition in the final program. Your C implementation (notably the compiler and the linker) appears to be doing this, and that would be why you did not get an error message.
(This was the default behavior for GCC prior to version 10. You can request the old behavior with -fcommon or the non-coalescing behavior with -fno-common. Some additional information is here and here.)
… and I also don't know if this approach would be considered 'good practice'
You have not shown much context for what you are doing or why. Generally, external identifiers for objects should be avoided, but there can be appropriate uses.

Typedef structure's member being static or not in c

I think this none sense doesnt that? because after creating instance from that variable. It will initialize that variable whole, will not behave differently to members an will initialize all of them, doesn't that? As I know static variables are global variable but their usage are restricted to specified function or source file.
typedef struct
{
const uint32_t mainpointer;
static uint32_t currentpointer;
uint16_t num_el;
uint8_t num_byte;
}arrayPushCirc_doublebuffer_instance;
void main(void)
{
arrayPushCirc_doublebuffer_instance struction;
function1(struction);
}
In C data members of a structure may not have storage class specifiers.
So this declaration of a data member
static uint32_t currentpointer;
is invalid in C.
According to the C Grammar data member declarations may have only the following specifiers
specifier-qualifier-list:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt
On the other hand, you may use the storage class specifier static for declarations of objects in the file scope or a function scope.
For example
#include <stdint.h>
typedef struct
{
const uint32_t mainpointer;
uint32_t currentpointer;
uint16_t num_el;
uint8_t num_byte;
}arrayPushCirc_doublebuffer_instance;
static arrayPushCirc_doublebuffer_instance struction;
int main( void )
{
//...
}
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )

Pointer to constant string in struct

I'm writing in C.
In header1.h I declare a pointer to a constant string (a constant array of char), a new type with a struct and a variable of this type, and another variable:
const char *str_ptr = "Hello world!";
struct entry_t {
const char *text;
int var;
};
typedef entry_t entry;
extern entry start_entry;
int a;
In the file func.c I define the new variable:
#include "header1.h"
entry start_entry = {str_ptr, a};
void func(void)
{
//here i use start_entry
}
But the compiler report me the error
constant expression required
referring to the initialization of start_entry, and in particular of the const char* member.
Why? Where is the error?
Naturally if I define the string as
const char str[] = "Hello world!";
and then the entry variable as
entry start_entry = {&str, a};
everything is ok.
EDIT_1
I've made two errors in reporting my code:
var is const too
struct entry_t {
const char *text;
const int var;
};
in func.c entry is const too
const entry start_entry;
EDIT_2
I don't care of var, my interest is on const char * member (even if maybe the problem is the same: i write wrong code before, also with int var i had an error...).
I'm going to redefine all:
//header1.h
const char *str_ptr = "Hello world!";
struct entry_t {
const char *text;
};
typedef entry_t entry;
extern const entry start_entry;
//func.c
#include header1.h
const entry start_entry = {str_ptr};
void func(void)
{
//here i use start_entry
}
I can't understand why start_entry has a const char* member, i define it with a const char* but there is that error.
You can only use compile-time constants in initializers. The variable str_ptr is not even a run-time constant. What the const qualifier does is to prevent the string pointed to by str_ptr from being modified. The pointer itself can be reassigned. Therefor you need to initialize your start entry in an initialization function instead:
#include "header1.h"
entry start_entry;
void func(void)
{
//here i use start_entry
}
void init(void)
{
start_entry.text = str_ptr;
start_entry.var = a;
}
The problem is that with a C compiler you cannot initialize such statements in the global scope, it is considered as code outside a function:
(the same way that you cannot call a function to get tis return value and initialize a global outside a function)
entry start_entry = {str_ptr, a};
str_ptr is not really considered as a constant in C since it is seen as a pointer. The const qualifier does nothing here.
(the problem also occurs for me with a BTW, it looks that you are using some strange C++ compiler or a special C99 option see pmg comment)
When simply calling g++, your example works.
Note about your "naturally" statement:
entry start_entry = {&str, a};
compiles (with your compiler, gcc still rejects it because of a) but since you pass the address of the pointer, not the pointer itself => unspecified behaviour: not good.
If you want to do that, I suggest that you use a C++ compiler.
What works with simple gcc call:
char str_ptr[] = "Hello world!";
entry start_entry = {str_ptr, 12}; // considered as an array, value decided by the compiler, even if const keyword is missing
What doesn't
const char *str_ptr = "Hello world!";
entry start_entry = {str_ptr, 12}; // str_ptr is considered as a variable pointer even if const
entry start_entry = {"Hello world!", a}; // a is a variable: nocantdo
Where you are right is that char [] tells the compiler that the pointer is constant, even without the const keyword BTW, whereas the const keyword is not taken into account.
Notes:
I had to fix your code so it compiles with my gcc compiler:
typedef struct {
const char *text;
int var;
} entry;
extern entry start_entry;
Another point is: avoid declaring globals in header files as you'll get multiple inclusions or undefined symbols if you have more than one code file including it.

Initialize a struct

I am trying to initialize a struct but getting the following error messages in C:
error: initializer element is not constant
error: (near initialization for 'resource01.resource.role')
For URL it works, it's just the role which is not working. First I had a pointer on role and I assigned the address of the variable. I removed the pointer because I don't need it and I can t assign just a value to the variable. What am I doing wrong?
static char const resource01Url[] = "/dummy";
static int const resource01Role = 2;
static struct RestResourceNode_S resource01 =
{
{
resource01Url,
resource01Role,
&DummyHandler_call
},
NULL
};
static struct RestResourcesManager_S resourcesManager =
{
&resource01, &resource01
};
The type RestResourceNode_S is defined:
struct RestResourceNode_S
{
RestResource_T resource;
struct RestResourceNode_S const *next;
}
and RestResource_t:
struct RestResource_S
{
char const *url;
int const role;
retcode_t (*handle)(Msg_T *);
};
typedef struct RestResource_S RestResource_T;
The C99 standard §6.7.8 ¶4 says
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
Also, const are not true constants in C in the sense that they are not compile-time constant. This means that you cannot have a constant object in the initializer of a structure which has static storage allocation. However, if your structure has automatic storage allocation, this would work fine.
What you can do is define your const objects as macros -
#define resource01Url "/dummy"
#define resource01Role 2
int const does not count as a compile-time constant in C. You will have to change it to a #define instead.

How to apply the sizeof operator to a function pointer and initialize a structure?

The folowing piec of code generates error: initializer element is not constant
at compile time on the line declaring and initializing the user struct variable.
#include <stdio.h>
#include <stdlib.h>
struct user_s {
char *name;
void (*(*pred_skip_func))(int);
};
void f1 (int skip) {
printf("I am f1\n");
}
void f2 (int skip) {
printf("I am f2\n");
}
void (*(*pred_skip_func))(int);
struct user_s user = {"Manu", pred_skip_func};
int main(void) {
struct user_s tmp;
pred_skip_func = malloc(sizeof(tmp.pred_skip_func) * 2);
pred_skip_func[0] = f1;
pred_skip_func[1] = f2;
int i;
for (i = 0; i < 2; i++) {
(*(user.pred_skip_func)[i]) (i);
}
return EXIT_SUCCESS;
}
Moving the initialization in the main function solves the issue, but I want to understand why ? Is there any restriction on structure initialisation ?
More over, as you can see, I created a tmp user_struc variable to get the size of my pointer to function pointers because I was not able to do this in a cleaner way. How can I fix this ?
First question:
"Is there any restriction on structure initialisation ?"
C requires initializers for aggregate types with static storage duration to be constant:
(C99, 6.7.8p4) "All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals."
Note that in C89 even if the object of the aggregate type had automatic storage duration the intializers had to be constant expressions (this is no longer the case in C99).
Second question:
"More over, as you can see, I created a tmp user_struc variable to get the size of my pointer to function pointers because I was not able to do this in a cleaner way."
You can use your user object to compute the size of the member:
sizeof (user.pred_skip_func)
or use a C99 compound literal if you have not declared any object of the structure type:
sizeof (((struct user_s) {0}).pred_skip_func)
As #ouah points out, the problem is that pred_skip_func is not a constant value. The compiler complains because user has static storage duration, which means its bitwise representation is going to be "baked in" the executable image at link time. In order for this representation to be known to the linker the value for pred_skip_func must be a constant.
However, you can specify a "sane default" constant value for the struct member very easily:
struct user_s user = {"Manu", 0};
You can go for typedefs for function pointer like below.
typedef void (*pfunc_type)(int);
struct user_s
{
char *name;
pfunc_type *pred_skip_func;
};
.....
int main (void)
{
.....
pred_skip_func = (pfunc_type *)malloc(sizeof(pfunc_type) * 2);
.....
}
This will increase the readablity of your program.

Resources