const pointer pointing to a const pointer - c

I'm working with some memory pointers. I don't want to use hash defines, please leave that discussion aside. I would just like to know why this does not compile:
#include <stdio.h>
static const unsigned long *const pMemAddrA = (unsigned long *) 0x00000200ul;
static const unsigned long *const pMemAddrB = pMemAddrA;
int main (void)
{
printf("%x", (unsigned int) pMemAddrB);
return 0;
}
Compiler output gcc:
||=== TestConst, Debug ===|
...main.c|4|error: initializer element is not constant|
||=== Build finished: 1 errors, 0 warnings ===|
EDIT:
After reading the answers, I'm happy to know how to go about this problem.
However I do not understand why it is a problem. From what I know static memory gets allocated at program start. I know there is issue if variables "live" in different files and the order in which the variables are allocated cannot be guaranteed by the compiler. However, if both variables "live" in the same file - just as both variables living in the same function - I would think the compiler can assure that memory gets allocated in the order of variables being declared in the file, and therefore I don't understand why declaring and initializing a const pointer to another const pointer is an issue. I'd be happy if someone could enlighten me.

Your pointers have file scope, so the initialisers must be constant expressions. pMemAddrA isn't a constant expression, therefore can't be used to initialise a variable with static storage.
It can be used to initialise a variable in block scope, so if you move your declarations inside main (and make at least the second non-static), it will compile:
#include <stdio.h>
int main (void)
{
const unsigned long *const pMemAddrA = (unsigned long *) 0x00000200ul;
const unsigned long *const pMemAddrB = pMemAddrA;
printf("%x", (unsigned int) pMemAddrB);
return 0;
}
If the two pointers must be declared at file scope, there is no way to prevent either repeating the initialising expression,
static const unsigned long *const pMemAddrA = (unsigned long *) 0x00000200ul;
static const unsigned long *const pMemAddrB = (unsigned long *) 0x00000200ul;
or #defineing it.

You don't describe what "does not work", but I guess you mean that the line
static const unsigned long *const pMemAddrB = pMemAddrA;
produces the error
error: initializer element is not constant
.
The solution is that indeed this initializer is not considered as constant. Instead, a memory area for pMemAddrA is set aside and the value 0x00000200ul is written in there. From there on, it is a value which sits somewhere in memory, and not a constant expression.
Depending on what you want to do with that, you could add another pointer indirection such as
static const unsigned long *const * const pMemAddrB = &pMemAddrA;
and access it with *pMemAddrB instead of pMemAddrB.

Related

How to use const pointers inside structures?

hope everyone is doing great!
I was trying to implement some lib in embbeded enviroment, where i need to use const pointers.
Here is the code i was trying to do:
#include <stdio.h>
int a = 10;
typedef struct {
void * const payload;
int size;
} msg;
typedef struct {
void * const payload2encode;
int size2encode;
} encode_msg;
msg message[1] = {
{
/* payload */ &a,
0
}
};
encode_msg encoded_message = {
/* payload */ message[0].payload,
0
};
int main(void){
return 0;
}
but i'm getting the following error:
main.c:23:19: error: initializer element is not constant 23 |
/* payload */ message[0].payload,
If I change 'message[0].payload' to '&a' the code runs fine. I don't get why this is happening :(. Anyone know why?
Best reggards!
There are a lot of misconceptions here.
First of all, why do you need a "constant pointer"? This message here:
error: initializer element is not constant
Does not mean "the compiler wants a constant pointer", but rather "I want a a compile-time constant such as an integer constant expression". This has nothing to do with const at all in C (C++ is another story), but this:
A variable with static storage duration, like one declared at file scope outside any function, must be initialized with a constant expression. Such as an integer constant expression or in case of pointers the address of another variable. But it cannot be initialized to the value of a different variable. Simple example:
int a = 0;
int b = a; // error: initializer element is not constant
That's just how the language works. You could initialize a pointer to an address however, since address constants are constant expressions. That's why /* payload */ &a, works.
Next misconception: there is nothing called "constant pointer". There are:
pointers to read-only data, const type* name.
read-only pointers to read/write data: type* const name.
read-only pointers to read-only data: const type* const name.
For some reason you picked the second of these options (took a gamble?). It has limited uses, but one valid use of it is to declare read-only pointer variables in ROM on embedded systems with true ROM like flash.
Also we usually don't want to use qualifiers like const inside a struct on an individual member if we can avoid it. Because then the struct variable itself ends up with different qualifiers than it's members. Normally we want the whole struct to be const or nothing in the struct at all. In embedded systems we also need to consider if we want it to be stored in RAM or flash.
Regarding void*, they are not very suitable to use for any purpose in an embedded system. uint8_t* boiling down to a character pointer is much more useful, since it can be used to access any other type byte by byte. Whereas a void* has to be converted to another type before we can do anything meaningful with it. Type-generic programming in embedded systems is also a bad idea most of the time, since such systems should behave deterministically.
encoded_message has static storage duration (because it's declared outside any function) and so must be initialized with a constant expression, and message[0].payload isn't (it's a const variable, but not a constant expression).
You can either declare encoded_message in a function (main, for instance), or, if your compiler supports it, make message const as well.
See also : Error "initializer element is not constant" when trying to initialize variable with const

I keep seeing const char * const parameters, I know the second const is pointless for a stack copy so why are they doing it?

First off let me state that I understand the difference between:
const char *a;
and
char * const a;
and
const char * const a;
However lately I am repeatedly encountering the latter when being used to pass parameters to a function, to give an example the Maxmind GeoLite2 mmdb C API for reading the database files uses the following format for every pointer parameter:
const T * const
Example:
https://github.com/maxmind/libmaxminddb/blob/master/include/maxminddb.h#L203
extern int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb);
I have a solid understanding of C/C++ and the x86 or x86-64 that C/C++ is often compiled into and I understand that the pointer to the filename and the pointer to the MMDB_s are both stack-allocated copies (or passed by register in the case of x86-64) so what purpose is there to make the pointer const?
Am I missing something here or are they unnecessarily flooding their API with const pointers which really have no end effect on the person using them?
The C standard specifically says that top-level const qualifiers are ignored in function prototype declarations. (N1570 §6.7.6.3p15, the sentence in parentheses at the very end of the paragraph.) What that means is, from the perspective of code trying to call MMDB_open, the declarations
extern int MMDB_open(const char *const filename, uint32_t flags,
MMDB_s *const mmdb);
and
extern int MMDB_open(const char *filename, uint32_t flags,
MMDB_s *mmdb);
are semantically the same. So you are correct to think that these qualifiers are unnecessary.
However, they are not pointless, because, from the perspective of the implementation of the function, they are not the same. Inside the code for MMDB, they have this function definition somewhere
int
MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
{
// code here
}
and the code in the body of this function is not allowed to modify the filename and mmdb variables (but it is allowed to write through mmdb and modify what it points to). That's why they put the qualifiers on those variables in the first place.
And they probably copied the qualifiers into the prototypes in the public header files because they wanted the prototypes to match up to the function definitions exactly. That makes maintaining the header file easier.

Initializing global variable works with integer literal but not with const type variable [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 7 years ago.
I'm working through some openGL tutorials and since they all have C++ syntax I need to convert them to C syntax and I have some problems with global variables.
So I have my extern declarations in the shared header LUtil.h
#ifndef LUTIL_H
#define LUTIL_H
#include "LOpenGL.h"
#include <stdio.h>
#include <stdbool.h>
//Color modes
extern const int COLOR_MODE_CYAN;
extern const int COLOR_MODE_MULTI;
//Screen constants
extern const int SCREEN_WIDTH;
extern const int SCREEN_HEIGHT;
extern const int SCREEN_FPS;
extern int gColorMode;
extern GLfloat gProjectionScale;
...
And I have my LUtil.c file in which the declaration happens
#include "LUtil.h"
//The current color rendering mode
const int COLOR_MODE_CYAN = 0;
const int COLOR_MODE_MULTI = 1;
//constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_FPS = 60;
//The projection scale
int gColorMode = 0;
GLfloat gProjectionScale = 1.f;
...
Now if I compile like this it works. But if I initialize the gColorMode constant like this in LUtil.c
int gColorMode = COLOR_MODE_CYAN;
I get a compiler error saying that my initializer is not constant despite having declared COLOR_MODE_CYAN a const and initializing with it.
Why is this?
In C, a variable declared const is not a constant, it's called const-qualified variable. It is not considered a compile time constant expression.
You need to either use an integer constant or a #define to get your work done.
FWIW, a variable with const is a real constant (integral constant expression) in case of C++.
const in C doesn't actually create a "constant". You still end up with a variable (reserved memory) but the compiler just forbids writes to that variable.
Even though it is marked const, you could cast it back to non-const and modify it (please don't!) Because of this (and possibly other reasons), it requires emitting a memory read to access the value of your const int constants, which is not allowed when initializing another variable (it must be a compile-time constant.)
Instead, use a #define in your header file.
const int COLOR_MODE_CYAN
is still a variable even if it is constant(which just means that compiler will throw a compile time error if you try to modify it using code). Which means it will have a memory location and a value, when the program will be loaded into memory. Its value can be calculated by the = operator. And all the operators should be placed inside a function definition because they can be resolved only at run time.
And since the variable which you are assigning the value to is a global variable. Its initial value must be declared at compile time so that the compiler can put it into an appropriate segment(.bss or .data). But the assigned value is a variable, and in order to find out its value = operator has to be executed. Which can not be done at compile time. So that compiler is throwing an error that GIVE ME A CONSTANT VALUE THAT I CAN ASSIGN TO THIS GLOBAL VARIABLE LIKE 3, 4, 5.

Have compiler declare and locate debug pointer variable

Say I have a two functions like the ones below:
unsigned char PlusTwo(unsigned char value)
{
return (value + 2);
}
unsigned char PlusTwoUsingPtr(unsigned char *value)
{
return (*value + 2);
}
If I want to test the first function while I'm developing, no problem, all I have to do is this:
PlusTwo(8);
The compiler will automatically place a constant somewhere in memory for me. However, to test the second function, it gets more complicated. First I have to declare a variable, then pass the function the address of the variable:
unsigned char eight = 8;
PlusTwoUsingPtr(&eight);
This isn't horribly time consuming, but it is annoying (particularly in C89/ANSI where variables have to be declared at the beginning of a function block). Is there some trick that will allow me to just test this function in one line of code, having the compiler declare & place a constant somewhere for me to point to?
You can use a compound literal with a scalar type:
PlusTwoUsingPtr(&((unsigned char){8}));
Compound literal is a feature introduced in C99.
For information the object is mutable (with static storage duration) and you can also modify it in your function.

What are the implications of using static const instead of #define?

gcc complains about this:
#include <stdio.h>
static const int YY = 1024;
extern int main(int argc, char*argv[])
{
static char x[YY];
}
$ gcc -c test1.c
test1.c: In function main':
test1.c:5: error: storage size ofx' isn't constant
test1.c:5: error: size of variable `x' is too large
Remove the “static” from the definition of x and all is well.
I'm not exactly clear what's going on here: surely YY is constant?
I had always assumed that the "static const" approach was preferable to "#define". Is there any way of using "static const" in this situation?
In C, a const variable isn't a "real" compile-time constant... it's really just a normal variable that you're not allowed to modify. Because of this, you can't use a const int variable to specify the size of an array.
Now, gcc has an extension that allows you to specify the size of an array at runtime if the array is created on the stack. This is why, when you leave off the static from the definition of x, the code compiles. However, this would still not be legal in standard C.
The solution: Use a #define.
Edit: Note that this is a point in which C and C++ differ. In C++, a const int is a real compile-time constant and can be used to specify the size of arrays and the like.
You may use 'enum' or 'define' to declare the size:
#define XX 1024
static int const YY = 1024;
enum{ ZZ = 1024 };
extern int main(void){
static char x[XX]; // no error
*(int*)&XX = 123; // error: lvalue required as unary ‘&’ operand
static char y[YY]; // error: storage size of ‘y’ isn’t constant
*(int*)&YY = 123; // no error, the value of a const may change
static char z[ZZ]; // no error
*(int*)&ZZ = 123; // error: lvalue required as unary ‘&’ operand
}
Because you declared x as 'static' that makes it a global variable. Its just known only to the main() function in which it is declared. By declaring YY outside of any function, you have made it global. 'static' also makes it a global, but known only to this file.
If you declared YY as just 'const int YY = 1024', the compiler might treat it like a #define, but with a type. That depends on the compiler.
At this point 2 things might be wrong.
1:
All globals are initialized at runtime, before main() is called.
Since both x and YY are globals, they are both initialized then.
So, the runtime initialization of global x will have to allocate space according to the value in YY. If the compiler is not treating YY like #define with a type, it has to make a compile-time judgement about runtime values. It may be assuming the largest possible value for an int, which really would be too big. (Or possibly negative since you left it signed.)
It may be interesting to see what happens if you only change YY to a short, preferably an unsigned short. Then its max would be 64K.
2:
The size of global space may be limited on your system. You didn't specify the target platform and OS, but some have only so much.
Since you declared x as size YY, you have set it to take YY chars from global space. Every char in it would essentially be a global. If the global space on your system is limited, then 1024 chars of it may be too much.
If you declared x as a pointer to char, then it would take sizeof(char*) bytes. (4 bytes is the size of a pointer on most systems.) With this, you would need to set the pointer to the address of properly malloc'd space.
By declaring x without 'static', it becomes a local variable and is only initialized once the owning function is executed. And its space is taken from the stack, not global space. (This can still be a problem for systems or threads with very limited stack.) YY's value has long since been set by this point, so there is no problem.
Also:
I don't recall if there is any guarantee that globals are initialized in any order. If not, then x could be initialized before YY. If that happened then YY would just contain the random contents of RAM.
To follow on from Martin B's answer, you could do this:
#include <stdio.h>
#define XSIZE 1024
static const int YY = XSIZE;
int main(int argc, char*argv[])
{
static char x[XSIZE];
}
/* SHOULDN'T THIS WORK IN C++? */
// .h
class C {
public:
static const int kSIZE;
int a[kSIZE]; // error: array bound is not an integer constant
};
// .cc
const int C::kSIZE = 1;
/* WORKS FINE */
// .h
class C {
public:
enum eCONST { kSIZE = 1 };
int a[kSIZE];
};

Resources