How can I add 2 ints in a const definition in 1990? - c

Welcome to the 1990s,
I am using an old Mac os 7.01 API, and I need to define a "Rect" struct with an array of four constants. Sadly, I always get the "requires constant" error on that "Rect" definition. We are talking about a 24 year old compiler, though.
Rect shapeRect = {100, 100, 200, 200}; // Works
const int shapeSize = 10;
int shapeX = 0; // Cannot be const
int shapeY = 0; // Cannot be const
Rect shapeRect = {shapeX - shapeSize, shapeY - shapeSize, shapeX + shapeSize, shapeY + shapeSize }; // Error: "requires constant"
I've tried defining multiple const with all the 4 values calculated, but I still get the same error on the same line.
const shapeRectT = shapeX - shapeSize;
...
Rect shapeRect - {shapeRectT, ...};
My guess is that the shapeRectT const is not a constant? I am a beginner in C, but I believe this problem is probably easy to repair, but this is an old compiler, and things may be different, and I don't know if newer C standards changed things about this stuff.
EDIT: I found the documentation for this API (QuickDraw): https://developer.apple.com/legacy/library/documentation/mac/pdf/ImagingWithQuickDraw.pdf

The problem is related to limitations of C89 that we all now have forgotten.
At that time you could not have non-litterals in the initializer of a global struct variable. Non-litteral expressions were only allowed for local struct variables.
This restriction was due to the fact that the code execution really started in those time with main() (in fact a stub initializing stdin,stdout and the environment and then calling main). There was no code generated for global initialisation. Only values that where loaded as part of the image from the executable.
I just could confirm this behaviour with my old microsoft compiler. It was MSDOS, but from February 1990, so pretty close to the one you use:
struct R {int a, b; }; /* simple structure for the demo */
struct R a = { 1,2 }; /* global variable with litteral init: ok ! */
const int v1 =10;
const int v2 =20;
struct R z = { v1,v2 }; /* Error message, "illegal initialization" */
int main()
{
struct R w = { v1,v2}; /* here it is accepted, because corresponding
initialisation code could be generated/executed
as part of the function */
return 0;
}

Yes, there is a difference in aggregate (and union) initialization between C89 and C99. A quote from the C99 rationale (PDF page 95):
The C89 Committee considered proposals for permitting automatic aggregate initializers to consist of a brace-enclosed series of arbitrary execution-time expressions, instead of just those usable for a translation-time static initializer. Rather than determine a set of rules which would avoid pathological cases and yet not seem too arbitrary, the C89 Committee elected to permit only static initializers. This was reconsidered and execution-time expressions are valid in C99.
Some C89 compilers implement this as extension. Yours doesn't. You can fix the error like this:
Rect shapeRect;
shapeRect.top = shapeX - shapeSize;
shapeRect.left = shapeY - shapeSize;
shapeRect.bottom = shapeX + shapeSize;
shapeRect.right = shapeY + shapeSize;

Do it manually. (Not recommended.)
Make some constants you use for initializing (not const-qualified variables).
enum {shapeX_Init = 0, shapeY_Init = 0, shapeSize_Init = 10};
const int shapeSize = shapeSize_Init;
int shapeX = shapeX_Init; // Cannot be const
int shapeY = shapeY_Init; // Cannot be const
Rect shapeRect = {shapeX_Init - shapeSize_Init, shapeY_Init - shapeSize_Init,
shapeX_Init + shapeSize_Init, shapeY_Init + shapeSize_Init };

Related

Is it a good practice to group related constants using structs in C?

I was wondering if it would be a good idea to use structs as pseudo namespaces (à la C++) to group constants which are functionally or conceptually related to each other.
static const struct {
const unsigned int START;
const unsigned int END;
} COUNTER = {.START = 1, .END = 100};
Is there any downside to this? If not, is it redundant (or maybe even unconvenient) to have both the struct instance and its members declared as const? Where should the constantness of these values be stated?
I was wondering if it would be a good idea to use structs as pseudo namespaces
Well, it CAN be a good idea. It's not intrinsically bad. An argument against is that if you feel that you need namespaces, then it's likely that C is the wrong language in the first place. But it can be used this way, and it is sometimes used this way.
Where should the constantness of these values be stated?
It's in general enough to declare the whole struct as const. But beware with pointers. This code is valid and will print "42":
int x = 5;
const struct {
int *p;
} S = {.p = &x };
int main()
{
*(S.p) = 42;
printf("%d\n", x);
}
In the above code, you are not allowed to change S.p so that it points to something else, but there is a difference between a const pointer and a pointer to const. So for pointer, it could be a good idea to add an extra const.
To clarify, the pointer p will be declared like it was a int * const p which means you cannot change the pointer itself, but in order to protect the data it's pointing to, you need const int *p. To get both, use const int * const p, but if the struct is declared as const, you'll get one of them "for free" so const int *p is enough to get both.
And if you consider pointers to pointers, well, think it through for a long time and test it to make sure it works the way you want.
From comments:
Why not enums?
Because this is not valid:
enum S {a = 5};
enum Y {a = 6};
The compiler will tell you that a is already defined. So enums is not good for emulating namespaces. Also, you cannot use enums for non-integers.
Is it a good practice to group related constants using structs in C?
It's opinion based. If it works for you, do it.
I wouldn't do like that i C. Instead I use #define
Like:
#define GROUPNAME_NAME
so in your case I would do
#define COUNTER_START 1
#define COUNTER_END 100
In C++ I would do:
const unsigned int COUNTER_START = 1;
const unsigned int COUNTER_END = 100;
The difference between C and C++ is due to differences in language specification.

How to assign a predefined value to a struct member on type definition?

This is a long shot, but maybe there will be some ideas. On a system I programming, I have defined structures to program processor registers. The registers are comprised of several fields of a few bits each, with potentially "reserved" bits in between. When writing to a register, the reserved bits must be written as zeros.
For example:
typedef struct {
uint32_t power : 3;
uint32_t reserved : 24;
uint32_t speed : 5;
} ctrl_t;
void set_ctrl()
{
ctrl_t r = {
.power = 1;
.speed = 22;
.reserved = 0;
}
uint32_t *addr = 0x12345678;
*addr = *((uint32_t *) &r);
return;
}
I want to be able to set the reserved field to a default value (0 in this example), and to spare the need for an explicit assignment (which happens a lot in our system).
Note that if the instantiated object is static, then by default an uninitialized field will be 0. However, in the above example there is no guarantee, and also I need to set any arbitrary value.
Structure type definitions in C cannot express values for structure members. There is no mechanism for it. Structure instance definitions can do.
I want to be able to set the reserved field to a default value (0 in
this example), and to spare the need for an explicit assignment (which
happens a lot in our system).
Note that if the instantiated object is static, then by default an
uninitialized field will be 0. However, in the above example there is
no guarantee, and also I need to set any arbitrary value.
That the default value you want is 0 is fortuitous. You seem to have a misunderstanding, though: you cannot partially initialize a C object. If you provide an initializer in your declaration of a structure object, then any members not explicitly initialized get the same value that they would do if the object had static storage duration and no initializer.
Thus, you can do this:
void set_ctrl() {
ctrl_t r = {
.power = 1,
.speed = 22,
// not needed:
// .reserved = 0
};
// ...
If you want an easy way to initialize the whole structure with a set of default values, some non-zero, then you could consider writing a macro for the initializer:
#define CTRL_INITIALIZER { .power = 1, .speed = 22 }
// ...
void set_other_ctrl() {
ctrl_t r = CTRL_INITIALIZER;
// ...
Similarly, you can define a macro for partial content of an initializer:
#define CTRL_DEFAULTS .power = 1 /* no .speed = 22 */
// ...
void set_other_ctrl() {
ctrl_t r = { CTRL_DEFAULTS, .speed = 22 };
// ...
In this case you can even override the defaults:
ctrl_t r = { CTRL_DEFAULTS, .power = 2, .speed = 22 };
... but it is important to remember to use only designated member initializers, as above, not undesignated values.
It can't be done.
Values don't have "constructors" in the C++ sense in C. There's no way to guarantee that arbitrary code is run whenever a value of a certain type is created, so this can't be done. In fact "creation" of a value is quite a lose concept in C.
Consider this:
char buf[sizeof (ctrl_t)];
ctrl_t * const my_ctrl = (ctrl_t *) buf;
In this code, the pointer assignment would have to also include code to set bits of buf to various defaults, in order for it to work like you want.
In C, "what you see is what you get" often holds and the generated code is typically quite predictable, or better due to optimizations. But that kind of "magic" side-effect is really not how C tends to work.
It is probably better to not expose the "raw" register, but instead abstract out the existance of reserved bits:
void set_ctrl(uint8_t power, uint8_t speed)
{
const uint32_t reg = ((uint32_t) power << 29) | speed;
*(uint32_t *) 0x12345678 = reg;
}
This explicitly computes reg in a way that sets the unused bits to 0. You might of course add asserts to make sure the 3- and 5-bit range limits are not exceeded.

Does using const global vars instead of enum ensure ABI compatibility?

In a C library project of mine I have an enum that lists all possible types a piece of data handled by the library can be:
// lib.h
enum types {
VOID,
INT,
FLOAT,
CONST_INT,
CONST_FLOAT
}
The code will be compiled into a shared library. In future versions of the library, I will be required to insert new entries into the enum and reorder existing ones. AFAIK this breaks ABI compatibility since the enum is not transformed into a set of symbols that ends up in the library, but rather causes whatever integer the compiler assigns to each entry to be hardcoded. Is that the case?
If so, would it be preferable to instead use constant global variables such that they make an appearance in the symbol table and I thus can change both order and the value assigned to each?
// lib.c
const int VOID = 1;
const int INT = 2;
const int FLOAT = 3;
const int CONST_INT = 4;
const int CONST_FLOAT = 5;
// lib.h
extern const int VOID;
extern const int INT;
extern const int FLOAT;
extern const int CONST_INT;
extern const int CONST_FLOAT;
You're right. If you plan to expand the enumered variables it could make incompatible the future versions of your libraries.
If you take a look to some of the most relevant sw around (i.e. MS or linux headers) you can see that the solutions adopted are mainly two:
Use defines
Still use enum, but assign a value per each entry
The latter makes the use of enum quite equal to defines, but retains the properties of enums.
In your case it could be:
// lib.h
enum types {
VOID = 0,
INT = 1,
FLOAT = 10,
CONST_INT = 12,
CONST_FLOAT = 13
}
Then when in future you will add other codes:
// lib.h
enum types {
VOID = 0,
INT = 1,
CUSTOM1 = 3,
FLOAT = 10,
CUSTOM2 = 11,
CONST_INT = 12,
CONST_FLOAT = 13,
CUSTOM4 = 20
}
The use of constant globals could have some problems, even to be optimized out and be replaced by constants.
best way is to place the enum in the header file for that library.
Changing the enum will still require re-compiling/linking etc of the library (no getting around that),
To assure each label in the enum has the specific value, the enum can be written similar to:
enum
{
label1 = 0,
label2 = 1,
label3 = 20,
label4 = 5
};
the results in anonymous enum, where each of the labels are visible and have the appropriate value.

Combine designated initializers and malloc in C99+?

Is there a nice way to combine designated initializers from C99, with the result of a malloc?
The following seems to have needless duplication:
typedef struct {
int a, b, c;
} Type;
Type *t = malloc(sizeof *t);
*t = (Type) {
.a = 2,
.b = 3,
.c = 5,
};
Can the use of Type, and *t be removed from the above code?
Since you asked ;) there is one tool in C to avoid explicit duplication of code, macros. That said I don't see a way not to repeat at least the name of the type. But in C++ they can't either, so C is at least as good :)
The easiest I see is
#define DESIGNATE_NEW(T, ...) \
memcpy(malloc(sizeof(T)), \
&(T const){ __VA_ARGS__ }, \
sizeof(T))
which would give
Type *t = DESIGNATE_NEW(Type,
.a = 2,
.b = 3,
.c = 5,
);
this has several advantages.
It initializes all members correctly, even on architectures with non
standard representations of the 0 for float types or pointers.
Other than Keith' version it is "coding style" acceptable since it is just an expression that looks like an initialization and anybody should immediately capture visually what the second code snipset is supposed to do.
NB: Observe the const in the macro, this allows several instances of the compound literal to be folded, if the compiler decides this to be relevant. Also there are means to have a variant where the list of designators is optional, see P99 below.
The disadvantage is the memcpy and I would be happier with an assignment. Second there is no check for failure of malloc before using the result, but one could probably come across with some weirdness to have the code exit nicely.
In P99 I go a slightly different way. There we always have an initialization function for a type, something like
inline
Type* Type_init(Type* t, int a, int b, int c) {
if (t) {
*t = (Type const){ .a = a, .b = b, .c = c };
}
return t;
}
which by macro magic can be made to provide default arguments for a, b and c if they are omitted. Then you can simply use something like
Type *t = P99_NEW(Type, 1, 2, 3);
in your application code. This is better, since it avoids dereferrencing the pointer when the call to malloc failed. On the other hand this reintroduces an order to the initializers, so not perfect either.
You can with a variadic macro. I'm not going to claim that this is a good idea, but it works:
#include <stdlib.h>
#include <stdio.h>
#define CREATE(type, ptr, ...) \
type *ptr = malloc(sizeof *ptr); \
if (ptr) *ptr = (type){__VA_ARGS__}
int main(void)
{
typedef struct {
int a, b, c;
} Type;
CREATE(Type, t, .a = 2, .b = 3, .c = 5);
printf("t->a = %d, t->b = %d, t->c = %d\n", t->a, t->b, t->c);
return 0;
}
Note that I wasn't able to use the usual do { ... } while (0) macro definition trick (it would create a new scope, and t wouldn't be visible), so you'd have to be careful about the context in which you use this.
Personally, I think I'm happier with the needless duplication.
No, that's the only way to use designated initializers. Without the (Type){}, the compiler doesn't know how to validate the contents.

C: Behaviour of the `const` keyword

I've been told that if I'm coding in ANSI C to declare in the order that the variables will be used, assert that pointers are not null and that indices are within bounds, and to initialize just before usage of the variable.
If I declare a const can I initialize it after a block of assertions and code?
In Java final initializations must occur at declaration, yet is it consistent through ANSI C implementations that I can initialize a const once, but not necessarily at the time of declaration?
The Java compiler has a small amount of flow logic to allow you to initalise final variables after their declaration. This is legal Java:
final int something;
if ( today == Friday )
something = 7;
else
something = 42;
Java will detect if any branches leave the final value undefined. It won't analyse the conditions, so this is not legal Java, even though it's logically similar:
final int something;
if ( today == Friday )
something = 7;
if ( today != Friday )
something = 42;
In ANSI C89, const variables ( other than extern ) must be initialised in the statement they are declared in.
const int something = ( today == Friday ) ? 7 : 42;
The extern modifier on a declaration tells the compiler that the variable is initialised in a different complation unit ( or elsewhere in this compilation unit ).
In ANSI C99, you can mix declarations and code, so you can declare and initialise a const variable after a block of assertions and code. Portability of 1999 ANSI C remains an issue.
A work around for C89 is to note that the rules for declarations preceding code work at block scope rather than function scope, so you can do this:
#include<stdio.h>
int main ( void )
{
printf ( "wibble\n" );
{
const int x = 10;
printf ( "x = %d\n", x );
}
return 0;
}
Be aware that even in C89, you can often move the definition closer to the point of first use by introducing a bare block just for the extra scope. Before:
int a, b, c;
a = 12;
// Do some stuff with a
b = 17;
// Do some stuff with a and b
c = 23;
// Do some stuff with a, b, and c
After:
int a = 12;
// Do some stuff with a
{
int b = 17
// Do some stuff with a and b
{
int c = 23;
// Do some stuff with a, b and c
}
}
With C99 of course, you can define variables other than at the beginning of a block:
int a = 12;
// Do some stuff with a
int b = 17
// Do some stuff with a and b
int c = 23;
// Do some stuff with a, b and c
const variables are read-only and must be initialised where they're defined.
This code produces error: assignment of read-only variable 'foo' (GCC 4):
const int foo;
foo = 4;
The same goes for const pointers (note here: const int * is not a const pointer, but a pointer to const):
int * const foo;
foo = 4;
Short of the block scope and C99 declaration methods other have shown, the answer is no; you cannot defer initialization of a const variable. Anyway, const is not very useful for local variables. The main times I use the const keyword in C are:
Pointers in function arguments (or local variable pointers based on arguments) where the function is honoring a contract not to modify the pointed-to data. The const keyword helps ensure that the function implementation respects the requirement not to modify (it requires special effort casting to get rid of const) and allows this requirement to propagate through multiple function calls.
For declaring compile-time constant tables (lookup tables, predefined permanent objects, etc.) which I want stored in a read-only section of the binary so they don't use extra physical resources at runtime.
I sometimes declare local variables const if I think it will assist the reader in understanding a function, but that's pretty rare.
You can't initialize the const after declaration within the function body, but you can just open one block after your assertions:
void func()
{
int y;
// Do assertions
assert(something);
{
int const x = 5;
// Function body
}
}
If you are talking of splitting a definition
const int x = 2;
into two parts:
const int x;
x = 2;
I'm afraid that's not possible in C.
If I were you, I would try to make sure I understand the intent of the coding rules that you describe. I doubt sane coding rules would prevent initializing variables (even non-const variables).
In response to various comments:
const int * p;
is not a declaration of a const variable. It is a declaration of a non-const pointer variable to a const int.
You can declare
extern const int x;
but you can still not initialize x after having executed code, assertion checks, etc.
If you'd like to cast away const on the LHS, use this:
const int n = 0;
*((int*)&n) = 23;

Resources