c - How to initialize a constant structure - c

I would like to avoid having constant values hardcoded in my C files, so I was wondering if i had a way to intialize a struct constant directly in a header file to use it everywhere i included the header file? (in the way #define works for constants with simple types)
All answers i found so far have been:
const int var = 5; /*in header*/
which only works in C++ (not C)
Using a C file to initialize the constant which is not what i'm looking for
The best answer to this post: How do I use extern to share variables between source files?
which seems a bit complicated...
Thanks in advance for the answers or help you can bring me! :)
EDIT : I am adding more details to my question.
I want to stock hardware parameters of the system i use in a structure :
struct parameters_Component1 {
int const1 = 5;
double const2 = 7,847
}
struct parameters_Component2 {
int const1 = 6;
double const2 = 9,3343
}
or a struct equivalent to
#define myConst 5;
I want to have those constants values regrouped in a header file i can access and modify rather than in my C code for organisation purpose

I would like to avoid having constant values hardcoded in my C files,
so I was wondering if i had a way to intialize a struct constant
directly in a header file to use it everywhere i included the header
file? (in the way #define works for constants with simple types)
You first need to get a clearer idea of what you mean, relative to the semantics of the C language. In C terminology, constants are syntactic constructs that represent specific values in source code. They do not have their own associated storage, and they are available only for built-in types. What you want is not a "constant" in this sense, or at least, C does not provide for structure constants in that sense. This has nothing whatever to do with the const type qualifier.
There are several things that C does offer in this general area:
structure initializers, which work similarly to constants for initializing objects of structure types;
objects having unmodifiable (const) structure type; and
compound literals of structure type.
Initializers
As their name suggests, initializers can be used in object declarations to initialize the declared objects. They are not values per se, however, so they cannot be assigned to objects post-declaration or otherwise used where an expression is required. You can define a macro that expands to an initializer, and this is sometimes done. Example
header1.h
struct my_struct { int x; int y; };
#define MY_STRUCT_INITIALIZER { .x = 0, .y = 0 }
code1.c
// ...
// This is initialization, not assignment:
struct my_struct s = MY_STRUCT_INITIALIZER;
An initializer has no storage of its own.
Unmodifiable objects
As in C++, any data type can be const-qualified to produce a type for objects that cannot be modified. Such objects thus must take their value from an initializer, or be function parameters, or else be declared in a way that causes them to be default-initialized, for being unmodifiable means there is no other way to define their values. Unlike an initializer, these are bona fide objects with data types and associated storage, and they can be used in any expression compatible with their type. Similarly, the identifiers associated with const objects must satisfy C's rules for scope and linkage, just like other identifiers. In particular, although there can be multiple declarations of any object with external (or internal) linkage, there can be only one definition of each.
External objects
If you want to use the same object "everywhere", then that implies external linkage. Good style then calls for that object to be declared in a header, but it cannot be defined in a header because that would result in duplicate definitions if the header were included in more than one translation unit. This is well supported by C via the following idiom:
header2.h
struct my_struct { int x; int y; };
// a declaration:
extern const struct my_struct shared_struct; // NOTE: explicit "extern" and no initializer
my_struct_stuff.c
#include "header2.h"
// a definition:
const struct my_struct shared_struct = { .x = 1, .y = 2 };
other.c
#include "header2.h"
// no definition of shared_struct here
// ...
int x = shared_struct.x;
int y = shared_struct.y;
// ...
This affords a single unmodifiable object, shared among as many translation units as you like, but it does not satisfy your criterion of keeping everything in a header. It is possible to play conditional compilation games to get the definition to appear lexically in the header, but you still need exactly one designated source file that makes provision for providing the definition. (Details left as an exercise.)
Internal objects
Alternatively, if it is sufficient to use an equivalent but different object in each translation unit, then your header can define an unmodifiable object whose identifier has internal linkage. Each translation unit that includes the header will then have its own, independent copy of the object:
header3.h
struct my_struct { int x; int y; };
static const struct my_struct local_struct = { .x = 1, .y = 2 };
This satisfies your criterion of keeping everything in the header file, but you may have reason, even apart from storage-use considerations, for wanting to provide the same object to each translation unit, and this does not achieve that objective. Also, your compiler may emit warnings for translation units that include the header but do not access local_struct.
Compound literals
C also has compound literals of structure types, which are analogous in some ways to string literals. They represent bona fide objects, with data types and storage, and have a lexical form that conveys the objects' values directly. Compound literals may have const-qualified types, but they are not const by default, and in general, it is acceptable to modify an object corresponding to a compound literal in any way permitted by its type. Also, unlike string literals, compound literals do not necessarily have static storage duration. Furthermore, each appearance of a compound literal represents a separate object.
Lexically, a compound literal resembles a cast operator for a structure, union, or array type, applied to a corresponding initializer for an object of that type:
header4.h
struct my_struct { int x; int y; };
#define MY_STRUCT_LITERAL ((struct my_struct) { .x = 42, .y = 42 })
/* or:
#define MY_STRUCT_LITERAL ((const struct my_struct) { .x = 42, .y = 42 })
*/
Macros expanding to compound literals can be defined in headers, as shown, but it is important to understand that each appearance of such a macro will correspond to a separate object. Under some circumstances, the compiler might optimize out reserving any actual storage, but a compound literal is not a "constant" in the same sense as an integer or floating constant.
Overall
Your main available alternatives are presented above. It's unclear to me what or how much value you place on having the values appear lexically in a header file, as opposed to, say, in an accompanying for-purpose source file representing a translation unit. It's also unclear to me what relative importance you attribute to minimizing storage requirements for these data, or whether the object identities of the structures need to be significant. And inasmuch as you raised C++ in comparison, I should not overlook the fact that compound literals are a C feature that C++ does not provide. These are the considerations you should bear in mind in choosing among those possibilities.
Or you could also consider whether you really want to arrange the data in actual structure objects at all. I have focused on that because it's what you asked about, but there are macro-based options that would allow you to tabulate your data in a header, in fairly compact form, and use function-like macros instead of structure-access syntax to access them.

Related

why is not possible to have static members in struct?

First, from this:
static struct foo1 { //private struct, just for this file
int a;
};
int main (void) {
struct foo1 a = {10};
return 0;
}
question number 1
I will get warning:
warning: useless storage class specifier in empty declaration
};
What does it mean? Why is static "useless storage class specifier"? In other context (static local var in function, or global static, which I wanted to apply for the struct foo1, it would work).
question number 2
#include <stdbool.h>
static struct s_t{ //private struct (for this file only)
static bool is_there = false; // defaul (pre-defined) value for all instances
int value;
};
int main (void) {}
Why is not possible to have static, predefined value for all vars of type struct s_t in c? I just wanted to simulate the same functionality as is in function static local var -> preserve value across multiple calls, in that sense, I wanted have one member (bool is_there in this case) that preserve value across each var of type struct foo1 (instance of it). So why it is not possible?
question number 3
Also, can someone explain the error (in more general sense) from it:
error: expected specifier-qualifier-list before ‘static’
EDIT:
from comments, I do not really understand the concept of storage class, I know only from asm, there is data/text/bss segments, so does it mean static var has address in read-only part of memory? Or what is the concept of storage class in c related to asm?
Because static struct foo1 { ... is just a struct definition, not a variable. You should add static when you declare the instance of the struct. I prefer this style:
typedef struct {
int a;
}foo_t;
static foo_t a = {10};
Because C simply doesn't have static member variables like C++ does. In C, it's pretty useless to add storage- or type specifiers to a single struct member. Put it on the allocated variables instead.
TL;DR it's just not making any sense of your syntax since you can't have static there. Unless you are terribly interested about language grammar, there's nothing else to it.
static is a storage-class specifier and const etc are type qualifiers and int etc is a type specifier. The term specifier-qualifier list comes from formal C grammar of structs, which isn't terribly interesting to read unless you are making a compiler. When declaring a struct member you have two options (C17 6.7.2.1):
specifier-qualifier-list:
type-specifier specifier-qualifier-list(opt)
type-qualifier specifier-qualifier-list(opt)
static doesn't fit the bill of either, being a storage-class specifier, so the compiler is saying "what! this is not a specifier-qualifier list where I expected to find one, where is it?"
(And yeah it's recursive, so you can have multiple of type-specifier or type-qualifier such as const long const const int value;. Because C stands for Crazy.)
because struct is like a type or an object, when you declare a static member in C, it would be like:
static int a = 0;
In this case "int" is like the struct type you declared, so if you want to create a struct static member just do like this:
static s_t a;
static struct foo1 { //private struct, just for this file
int a;
};
The static declaration specifier only applies to object or function declarations, not type definitions. All you're doing in that statement is creating the struct foo1 type. Had you written something like
static struct foo1 {
int a;
} foo;
Then the object foo would be declared static.
If you declare the type within the .c file, it will only be visible within that .c file. The only way to make the type visible to multiple .c files is to declare it in a header and #include that header in each file that needs it.
Why is not possible to have static, predefined value for all vars of type struct s_t in c?
Because C struct types are simply not that sophisticated - they're just a way to define a data item with multiple attributes. The language doesn't provide any way to have members that are common across all instances of the type.
Remember that C is a product of the early 1970s and was originally developed to implement the Unix operating system - it was designed to be small, portable, and fast. A lot's been added to it over the last 40-some-odd years, but nothing that really changes the core philosophy of the language.
Well, its quite evident that you will get the warning. The reason is simple! You are trying to assign a Storage Class to the struct definition.
However, storage classes are applicable to variable declarations. Therefore, you are getting the prompt.
If you still wish to employ the static storage class, then you can do so with any variable, preferably, any instance of the structure.

use of #define to create a dummy record compatible with C89 std

How can I use #define to create a dummy record according to C89 standards?
I tried:
typedef struct foo{int a; int b;}foo;
#define DUMMY (foo) {.a=0, .b=0}
It works well but gives me a lot of warnings when I compile with -std=c89. Warnings say that this kind of thing is compatible only with C99 standards. Thanks anyone!!
In C89, the only values of aggregate (struct/union) type that can be used within a function are named objects, function return values, dereferenced pointers, or members of other aggregates. While C includes a construct which defines a character array initialized with constant data and yields it as an lvalue [i.e. a string literal], there is no equivalent for any other type.
As noted, if you can create a named static object, you could use:
static struct foo const doubleZero = {0,0};
#define DUMMY doubleZero
Use of the macro would be compatible with code that uses #ifdef DUMMY to determine whether it has already been defined.
If you needed the ability to create an object based upon parameters that might vary, you could use something like:
struct fooWrapper { struct foo dat[1]; };
struct fooWrapper makeFoo(int a, int b)
{ struct fooWrapper result; result[0].a=a; result[0].b=b; return result; }
#define MAKEFOO(a,b) (*(fooWrapper((a),(b)).dat))
which would then allow code to treat the result of MAKEFOO like an lvalue, thus allowing for e.g.
memcpy(whatever, &MAKEFOO(3,5), sizeof (struct foo));
The lifetime of the returned wrapper object wouldn't be quite as long as that of a C compound literal, but should be adequate for most purposes where that of a C compound literal would suffice.

Is a redeclaration of an untagged structure a compatible type?

For purposes expressed in this question, we want to do this:
typedef struct { int a; } A;
typedef struct { struct { int a; }; int b; } B;
A *BToA(B *b) { return (A *) b; }
B *AToB(A *a) { return (B *) a; }
The desire is that the casts conform to C 2011 6.7.2.1 15, which says “A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.”
Since the struct { int a; } inside B does not have a name, let’s call it A'.
“Suitably” is not explicitly defined. I presume that if b is a valid pointer to an object of type A', then (A *) b performs a suitable conversion, and, similarly, if a is a pointer to an A' that is in a B, then (B *) a is a suitable conversion.
So the question is: Is A * a valid pointer to an object of type A'?
Per 6.7.6.1, A * is compatible with A' * if A is compatible with A'.
Per 6.2.7, “Two types have compatible type if their types are the same… Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order…”
These cannot be the same type by 6.7.2.3 5: “Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.”
Since they are not the same type, are they compatible? The text in 6.2.7 says they are compatible if declared in separate translation units, but these are in the same translation unit.
As you laid out in the question, the standard clearly and unambiguously says that two struct definitions struct { int a; } in the same translation unit declare two incompatible types. Notwithstanding the fact that this might be "weird". Compilers have always followed the standard.
This seems like reasonable behaviour to me: if you happen to have semantically unrelated structs in your project that coincidentally have a member list with the same types, you do want the compiler to reject an accidental assignment between the two.
Re. the code in your question, according to 6.7.2.1/13,
The members of an anonymous structure or union are considered to be members of the containing structure or union.
So I would treat the definition of B as being equivalent to:
typedef struct { int a; int b; } B;
for purposes of further analysis.
I haven't seen anything in the standard that says that both struct are compatible and thus I would say that they are not.
The only thing that could get you a limited compatibility between the structures is the use of an union, as mentioned in 6.7.2.1§6:
One special guarantee is made in order to simplify the use of unions: if a union contains
several structures that share a common initial sequence (see below), and if the union
object currently contains one of these structures, it is permitted to inspect the common
initial part of any of them anywhere that a declaration of the completed type of the union
is visible.
i.e., something like
typedef struct { int a; } A;
typedef struct { union { struct { int a; }; A export; }; int b; } B;
A *BToA(B *b) { return &b->export; }
B *AToB(A *a) { return (B *) a; }
should be safe, but for read accesses only: the standard did not really bother to specify what "inspecting" the common initial sequence means, but seems to use it in opposition to "modify".
There are two situations in which compatibility of structures is relevant:
In deciding whether values or pointers of one type may be coerced into values or pointers of the other, without use of the casting operator and without producing a diagnostic. Note that for this purpose, separately-declared structures are incompatible even if they are structurally identical, but that this kind of compatibility is irrelevant when passing structures or pointers between compilation units.
In deciding whether a value of, or pointer to one type, may be safely given to code which expects the other. Passing untagged structures between compilation units would be impossible if structurally-identical types were not regarded as compatible for this purpose. Compilers used to regard structurally-identical types as compatible for this purpose even within a compilation unit, and there was never any good reason for compilers to do otherwise in cases where one or both types are untagged, but because the Standard doesn't mandate such treatment it has become fashionable for compilers to senselessly weaken the language by blithely assuming that a pointer to one such type won't be used to access members of another.
Unfortunately, when the Standard was written, its authors didn't think it was important to expressly mandate all the obviously-useful things that compilers were already doing, and which sensible compilers would continue to do. The net result is that useful constructs which used to be supported and non-controversial will be unreliable unless otherwise-useful optimizations are disabled.

Can enums have limited scope if defined inside a struct in c

I want to know if an enum can be limited in how it is access by putting it inside a struct. I know that this would work in C++ (that's where I got the idea), but I don't know if it will work in c. So, for example, if I have two different structs
struct SaticArrayA
{
enum { MAX_SIZE = 10 };
int array[MAX_SIZE];
};
struct SaticArrayB
{
enum { MAX_SIZE = 20 };
int array[MAX_SIZE];
};
Will this even close to compile? Basically, I want to do what I would do in C++ and give myself a common naming convention across "classes" so that I can ask any array what it's size is, etc.
(p.s. I'm essentially trying to give myself a nicer static array in c that won't lose size information (by decaying to a pointer) the second I try to pass it to another scope).
It will not compile,
you didn't give the enumerator a tag
enum { MAX_SIZE = 10 } name ;
and you declared two enumerator constants with the same name
MAX_SIZE
C11 standard on scopes of indentifiers:
6.2.1. p7 Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator
This means that your first enumerator has a scope in the entire file from the line it is declared onward.
The second enum declaration with the same name is not correct and should not compile.
It doesn't matter where enums are being declared for this rule, struct or not, once declared they are in file scope from that point on.

Enumeration Scope

If I have enums like:
enum EnumA
{
stuffA = 0
};
enum enumAA
{
stuffA = 1
};
What happens here when you refer to stuffA? I thought you would refer to them like EnumA.stuffA and EnumB.stuffA as in Java, but that doesn't seem to be the case in C.
enums don't introduce new scope.
In your example, the second enum wouldn't compile due to the stuffA name clash.
To avoid name clashes, it is a common practice to give the elements of an enum a common prefix. Different prefixes would be used for different enums:
enum EnumA
{
EA_stuffA = 0
};
enum EnumAA
{
EAA_stuffA = 1
};
The enumeration constants are in the global name space (more precisely, the ordinary identifiers name space, contrasted with the labels, tags, and structure/union member namespaces), so you get a compilation error on the second stuffA.
You cannot use two different values for the same enumeration name (nor the same value specified twice) in a single translation unit.
As the others already said enumeration constants must be unique in the actual scope where they are defined. But with them as with other identifiers it is allowed to redefine them in another scope. Eg.
enum EnumA
{
stuffA = 0
};
void func(void) {
enum enumAA
{
stuffA = 1
};
// do something
}
would be fine. But such redefinitions in different scopes are often frowned upon and should be well documented, otherwise you will quickly loose yourself and others.
As mentioned, this won't compile because stuffA is defined twice. Enum values are simply referred to by the enumeration (that is "stuffA" rather than EnumA.stuffA). You can even use them on types that aren't enums (such as integers). Enums are sometimes used this way with ints, similar to the way one would #define constants.
This answer shows how the rules of C 2018 preclude the same identifier from being used as a member of two different enumerations. It is a language-lawyer view, intended to show how this requirement arises out of the language of the standard.
6.2.3, “Name spaces of identifiers,” tells us:
If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:
…
— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
Thus, all enumerator constants and ordinary declarators exist in one name space. (The name spaces omitted above are for labels [for goto statements]; tags of structures, unions, and enumerations [the name after a struct, as in struct foo]; and members of structures or unions [each has its own name space]).
6.7, "Declarations," tells us in paragraph 5 that:
A definition of an identifier is a declaration for that identifier that:
…
for an enumeration constant, is the (only) declaration of the identifier;
…
So the standard indicates that there is only one definition of an enumeration constant. Additionally, 6.2.1, “Scopes of identifiers,” tells us in paragraph 1:
An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program. A member of an enumeration is called an enumeration constant.
Observe that this tells that if foo identifies an enumeration constant, it identifies a member of an enumeration—it is a particular member of a particular enumeration. It cannot identify both a member of enum A and a member of enum B. Therefore, if we had the code:
enum A { foo = 1 };
enum B { foo = 1 };
at the point where foo appears the second time, it is an identifier for foo in enum A, and therefore it cannot be a member of enum B.
(The sentence about an identifier denoting different entities at different points is introducing the concept of scope. Further paragraphs in that clause explain the concept of scope and the four kinds of scope: function, file, block, and function prototype. These do not affect the above analysis because the code above is within one scope.)
Depending on where you declare these enums, you could also declare new scopes using the namespace keyword.
NOTE: I wouldn't recommend doing this, I'm just noting that it's possible.
Instead, it would be better to use a prefix as noted in the other examples.
namespace EnumA
{
enum EnumA_e
{
stuffA = 0
};
};
namespace EnumAA
{
enum enumAA_e
{
stuffA = 1
};
};

Resources