Using 'const' in C, what porting trouble might that cause? - c

I would like to use 'const' in C interface functions to note that certain char * arguments are not modified by the function.
What trouble might this cause in porting this code to various platforms? Is support of 'const' in C code pretty standard? When did this become officially in C standard?

I can't imagine const not being supported by any compilers, so porting should be a non-issue. If you were to find such a beast, you could just put
#define const
Somewhere in a common header file to make all of the const keywords vanish. The runtime semantics of your program won't change at all (since your compiler didn't support the keyword anyway).

It's pretty standard. I think it came with C89.

It works in MSVC, which is the biggest obstacle to overcome with C portability.

Pretty much any modern compiler should handle const correctly. The popular choices definitely will support it. It's been in the standard since C89, IIRC.

As the other answers say, const is standard. The only issues you will run into is using it incorrectly. Pointer const can be tricky. Make sure you are consting the correct thing:
See the wikipedia article on const-correctness:
For pointer and reference types, the syntax is slightly more subtle. A pointer object can be declared as a const pointer or a pointer to a const object (or both). A const pointer cannot be reassigned to point to a different object from the one it is initially assigned, but it can be used to modify the object that it points to (called the "pointee"). Reference variables are thus an alternate syntax for const pointers. A pointer to a const object, on the other hand, can be reassigned to point to another object of the same type or of a convertible type, but it cannot be used to modify any object. A const pointer to a const object can also be declared and can neither be used to modify the pointee nor be reassigned to point to another object. The following code illustrates these subtleties:
void Foo( int * ptr,
int const * ptrToConst,
int * const constPtr,
int const * const constPtrToConst )
{
*ptr = 0; // OK: modifies the pointee
ptr = 0; // OK: modifies the pointer
*ptrToConst = 0; // Error! Cannot modify the pointee
ptrToConst = 0; // OK: modifies the pointer
*constPtr = 0; // OK: modifies the pointee
constPtr = 0; // Error! Cannot modify the pointer
*constPtrToConst = 0; // Error! Cannot modify the pointee
constPtrToConst = 0; // Error! Cannot modify the pointer
}

The implementation may place a const object that is not volatile in a read-only region of
storage.
(WG14/N1336 sec 6.7.3, footnote 117)
Some (cross) compilers are quirky about this; they treat non-const variables as those to be placed in RAM, and const variables as those to be placed in a real read-only memory device (EEPROM or Flash)
You will run into trouble in such cases, as type* and const type* will refer to different memory regions.
Consider:
void foo(const char* arg); /* intent is not to modify anything through arg, but arg refers to a memory location in ROM */
/* ... */
char bar[] = "abc";
const char baz[] = "def";
foo(bar); /* behavior is undefined! */
foo(baz); /* should be ok */
I'm not aware of a PC-based compiler that does this, but this seems common in microcontroller cross-compilers. I recently faced this issue when porting FatFs on ImageCraft's compiler for PSoC1 and had to #define away consts as Carl suggested.

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

When to use const void*?

I have this very simple test function that I'm using to figure out what's going on with the const qualifier.
int test(const int* dummy)
{
*dummy = 1;
return 0;
}
This one throws me an error with GCC 4.8.3.
Yet this one compiles:
int test(const int* dummy)
{
*(char*)dummy = 1;
return 0;
}
So it seems like the const qualifier works only if I use the argument without casting to another type.
Recently I've seen codes that used
test(const void* vpointer, ...)
At least for me, when I used void *, I tend to cast it to char for pointer arithmetic in stacks or for tracing. How can const void prevent subroutine functions from modifying the data at which vpointer is pointing?
const int *var;
const is a contract. By receiving a const int * parameter, you "tell" the caller that you (the called function) will not modify the objects the pointer points to.
Your second example explicitly breaks that contract by casting away the const qualifier and then modifying the object pointed by the received pointer. Never ever do this.
This "contract" is enforced by the compiler. *dummy = 1 won't compile. The cast is a way to bypass that, by telling the compiler that you really know what you are doing and to let you do it. Unfortunately the "I really know what I am doing" is usually not the case.
const can also be used by compiler to perform optimization it couldn't otherwise.
Undefined Behavior note:
Please note that while the cast itself is technically legal, modifying a value declared as const is Undefined Behavior. So technically, the original function is ok, as long as the pointer passed to it points to data declared mutable. Else it is Undefined Behavior.
more about this at the end of the post
As for motivation and use lets take the arguments of strcpy and memcpy functions:
char* strcpy( char* dest, const char* src );
void* memcpy( void* dest, const void* src, std::size_t count );
strcpy operates on char strings, memcpy operates on generic data. While I use strcpy as example, the following discussion is exactly the same for both, but with char * and const char * for strcpy and void * and const void * for memcpy:
dest is char * because in the buffer dest the function will put the copy. The function will modify the contents of this buffer, thus it is not const.
src is const char * because the function only reads the contents of the buffer src. It doesn't modify it.
Only by looking at the declaration of the function, a caller can assert all the above. By contract strcpy will not modify the content of the second buffer passed as argument.
const and void are orthogonal. That is all the discussion above about const applies to any type (int, char, void, ...)
void * is used in C for "generic" data.
Even more on Undefined Behavior:
Case 1:
int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object
*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable
Case 2:
const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.
I began with these examples because they are easier to understand. From here there is only one step to function arguments:
void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}
Case 1:
int a = 0;
foo(&a); // the write inside foo is legal
Case 2:
int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior
Again I must emphasize: unless you really know what you are doing, and all the people working in the present and in the future on the code are experts and understand this, and you have a good motivation, unless all the above are met, never cast away the constness!!
int test(const int* dummy)
{
*(char*)dummy = 1;
return 0;
}
No, this does not work. Casting away constness (with truly const data) is undefined behavior and your program will likely crash if, for example, the implementation put const data in ROM. The fact that "it works" doesn't change the fact that your code is ill-formed.
At least for me, when I used void*, I tend to cast it to char* for
pointer arithmetic in stacks or for tracing. How can const void*
prevent subroutine functions from modifying the data at which vpointer
is pointing?
A const void* means a pointer to some data that cannot be changed. In order to read it, yes, you have to cast it to concrete types such as char. But I said reading, not writing, which, again, is UB.
This is covered more in depth here. C allows you to entirely bypass type-safety: it's your job to prevent that.
It’s possible that a given compiler on a given OS could put some of its const data in read-only memory pages. If so, attempting to write to that location would fail in hardware, such as causing a general protection fault.
The const qualifier just means that writing there is undefined behavior. This means the language standard allows the program to crash if you do (or anything else). Despite that, C lets you shoot yourself in the foot if you think you know what you’re doing.
You can’t stop a subroutine from reinterpreting the bits you give it however it wants and running any machine instruction on them it wants. The library function you’re calling might even be written in assembler. But doing that to a const pointer is undefined behavior, and you really don’t want to invoke undefined behavior.
Off the top of my head, one rare example where it might make sense: suppose you’ve got a library that passes around handle parameters. How does it generate and use them? Internally, they might be pointers to data structures. So that’s an application where you might typedef const void* my_handle; so the compiler will throw an error if your clients try to dereference it or do arithmetic on it by mistake, then cast it back to a pointer to your data structure inside your library functions. It’s not the safest implementation, and you want to be careful about attackers who can pass arbitrary values to your library, but it’s very low-overhead.

Misunderstood code example

I was reading this book http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html and I stopped at one of the examples. In my opinion it is incorrect. I think, that there is no undefined behaviour. Am I wrong? Here it is:
Taking the address of a data object of a type which isn't const and
putting it into a pointer to the const-qualified version of the same
type is both safe and explicitly permitted; you will be able to use
the pointer to inspect the object, but not modify it. Putting the
address of a const type into a pointer to the unqualified type is much
more dangerous and consequently prohibited (although you can get
around this by using a cast). Here is an example:
#include <stdio.h>
#include <stdlib.h>
main(){
int i;
const int ci = 123;
/* declare a pointer to a const.. */
const int *cpi;
/* ordinary pointer to a non-const */
int *ncpi;
cpi = &ci;
ncpi = &i;
/*
* this is allowed
*/
cpi = ncpi;
/*
* this needs a cast
* because it is usually a big mistake,
* see what it permits below.
*/
ncpi = (int *)cpi;
/*
* now to get undefined behaviour...
* modify a const through a pointer
*/
*ncpi = 0;
exit(EXIT_SUCCESS);
}
Example 8.3
As the example shows, it is possible to take the address of a constant object, > generate a pointer
to a non-constant, then use the new pointer. This is an error in your
program and results in undefined behaviour.
In this example, ncpi finally points to i, not ci. So I think that that makes this example incorrect — there is no undefined behaviour in modifying a non-const variable via a pointer. Do you agree?
I agree: it is a flawed example. The code itself exhibits defined behavior.
The comment before the final assignment, *ncpi = 0;, disagrees with the code. Probably the author intended to do something different.
My first response was as if the code overwrote a const: I have revised my answer.
It's undefined because it might be stored in read only memory for example. This won't be the case on x86 systems, but here we have a whole slew of other problems, like aliasing issues if you enable heavy optimizations.
Either way, even just intuitively, why would you think modifying a const through a pointer to it that the compiler can't statically validate would be safe?

What are some practical uses for const-qualified variables in C?

As has been discussed in several recent questions, declaring const-qualified variables in C (as opposed to const variables in C++, or pointers to const in C) usually serves very little purpose. Most importantly, they cannot be used in constant expressions.
With that said, what are some legitimate uses of const qualified variables in C? I can think of a few which have come up recently in code I've worked with, but surely there must be others. Here's my list:
Using their addresses as special sentinel values for a pointer, so as never to compare equal to any other pointer. For example: char *sentinel(void) { static const char s; return &s; } or simply const char sentinel[1]; Since we only care about the address and it actually wouldn't matter if the object were written to, the only benefit of const is that compilers will generally store it in read-only memory that's backed by mmap of the executable file or a copy of the zero page.
Using const qualified variables to export values from a library (especially shared libraries), when the values could change with new versions of the library. In such cases, simply using #define in the library's interface header would not be a good approach because it would make the application dependent on the values of the constants in the particular version of the library it was built with.
Closely related to the previous use, sometimes you want to expose pre-defined objects from a library to the application (the quintessential examples being stdin, stdout, and stderr from the standard library). Using that example, extern FILE __stdin; #define stdin (&__stdin) would be a very bad implementation due to the way most systems implement shared libraries - usually they require the entire object (here, FILE) to be copied to an address determined when the application is linked, and introduce a dependency on the size of the object (the program will break if the library is rebuilt and the size of the object changes). Using a const pointer (not pointer-to-const) here fixes all the problems: extern FILE *const stdin;, where the const pointer is initialized to point to the pre-defined object (which itself is likely declared static) somewhere internal to the library.
Lookup tables for mathematical functions, character properties, etc. This is the obvious one I originally forgot to include, probably because I was thinking of individual const variables of arithmetic/pointer type, as that's where the question topic first came up. Thanks to Aidan for triggering me to remember.
As a variant on lookup tables, implementation of state machines. Aidan provided a detailed example as an answer. I've found the same concept is also often very useful without any function pointers, if you can encode the behavior/transitions from each state in terms of a few numeric parameters.
Anyone else have some clever, practical uses for const-qualified variables in C?
const is quite often used in embedded programming for mapping onto GPIO pins of a microcontroller. For example:
typedef unsigned char const volatile * const tInPort;
typedef unsigned char * const tOutPort;
tInPort my_input = (tInPort)0x00FA;
tOutPort my_output = (tOutPort)0x00FC;
Both of these prevent the programmer from accidentally changing the pointer itself which could be disastrous in some cases. The tInPort declaration also prevents the programmer from changing the input value.
Using volatile prevents the compiler from assuming that the most recent value for my_input will exist in cache. So any read from my_input will go directly to the bus and hence always read from the IO pins of the device.
For example:
void memset_type_thing(char *first, char *const last, const char value) {
while (first != last) *(first++) = value;
}
The fact that last can't be part of a constant-expression is neither here nor there. const is part of the type system, used to indicate a variable whose value will not change. There's no reason to modify the value of last in my function, so I declare it const.
I could not bother declaring it const, but then I could not bother using a statically typed language at all ;-)
PC-lint warning 429 follows from the expectation that a local pointer to an allocated object should be consumed
by copying it to another pointer or
by passing it to a "dirty" function (this should strip the "custodial" property of the pointer) or
by freeing it or
by passing it up the caller through a return statement or a pass-by-pointer parameter.
By "dirty" I mean a function whose corresponding pointer parameter has a non-const base type. The description of the warning absolves library functions such as strcpy() from the "dirty" label, apparently because none of such library functions takes ownership of the pointed object.
So when using static analysis tools such as PC-lint, the const qualifier of parameters of called functions keeps locally allocated memory regions accounted.
const can be useful for some cases where we use data to direct code in a specific way. For example, here's a pattern I use when writing state machines:
typedef enum { STATE1, STATE2, STATE3 } FsmState;
struct {
FsmState State;
int (*Callback)(void *Arg);
} const FsmCallbacks[] = {
{ STATE1, State1Callback },
{ STATE2, State2Callback },
{ STATE3, State3Callback }
};
int dispatch(FsmState State, void *Arg) {
int Index;
for(Index = 0; Index < sizeof(FsmCallbacks)/sizeof(FsmCallbacks[0]); Index++)
if(FsmCallbacks[Index].State == State)
return (*FsmCallbacks[Index].Callback)(Arg);
}
This is analogous to something like:
int dispatch(FsmState State, void *Arg) {
switch(State) {
case STATE1:
return State1Callback(Arg);
case STATE2:
return State2Callback(Arg);
case STATE3:
return State3Callback(Arg);
}
}
but is easier for me to maintain, especially in cases where there's more complicated behavior associated with the states. For example, if we wanted to have a state-specific abort mechanism, we'd change the struct definition to:
struct {
FsmState State;
int (*Callback)(void *Arg);
void (*Abort)(void *Arg);
} const FsmCallbacks[] = {...};
and I don't need to modify both the abort and dispatch routines for the new state. I use const to prevent the table from changing at runtime.
A const variable is useful when the type is not one that has usable literals, i.e., anything other than a number. For pointers, you already give an example (stdin and co) where you could use #define, but you'd get an lvalue that could easily be assigned to. Another example is struct and union types, for which there are no assignable literals (only initializers). Consider for instance a reasonable C89 implementation of complex numbers:
typedef struct {double Re; double Im;} Complex;
const Complex Complex_0 = {0, 0};
const Complex Complex_I = {0, 1}; /* etc. */
Sometimes you just need to have a stored object and not a literal, because you need to pass the data to a polymorphic function that expects a void* and a size_t. Here's an example from the cryptoki API (a.k.a. PKCS#11): many functions require a list of arguments passed as an array of CK_ATTRIBUTE, which is basically defined as
typedef struct {
CK_ATTRIBUTE_TYPE type;
void *pValue;
unsigned long ulValueLen;
} CK_ATTRIBUTE;
typedef unsigned char CK_BBOOL;
so in your application, for a boolean-valued attribute you need to pass a pointer to a byte containing 0 or 1:
CK_BBOOL ck_false = 0;
CK_ATTRIBUTE template[] = {
{CKA_PRIVATE, &ck_false, sizeof(ck_false)},
... };
They can be used for memory-mapped peripherals or registers that cannot be changed by user code, only some internal mechanism of the microprocessor. Eg. on the PIC32MX, certain registers indicating program state are qualified const volatile - so you can read them, and the compiler won't try to optimise out, say, repeated accesses, but your code cannot write to them.
(I don't any code to hand, so I can't cite a good example right now.)

Should useless type qualifiers on return types be used, for clarity?

Our static analysis tool complains about a "useless type qualifier on return type" when we have prototypes in header files such as:
const int foo();
We defined it this way because the function is returning a constant that will never change, thinking that the API seemed clearer with const in place.
I feel like this is similar to explicitly initializing global variables to zero for clarity, even though the C standard already states that all globals will be initialized to zero if not explicitly initialized. At the end of the day, it really doesn't matter. (But the static analysis tool doesn't complain about that.)
My question is, is there any reason that this could cause a problem? Should we ignore the errors generated by the tool, or should we placate the tool at the possible cost of a less clear and consistent API? (It returns other const char* constants that the tool doesn't have a problem with.)
It's usually better for your code to describe as accurately as possible what's going on. You're getting this warning because the const in const int foo(); is basically meaningless. The API only seems clearer if you don't know what the const keyword means. Don't overload meaning like that; static is bad enough as it is, and there's no reason to add the potential for more confusion.
const char * means something different than const int does, which is why your tool doesn't complain about it. The former is a pointer to a constant string, meaning any code calling the function returning that type shouldn't try to modify the contents of the string (it might be in ROM for example). In the latter case, the system has no way to enforce that you not make changes to the returned int, so the qualifier is meaningless. A closer parallel to the return types would be:
const int foo();
char * const foo2();
which will both cause your static analysis to give the warning - adding a const qualifier to a return value is a meaningless operation. It only makes sense when you have a a reference parameter (or return type), like your const char * example.
In fact, I just made a little test program, and GCC even explicitly warns about this problem:
test.c:6: warning: type qualifiers ignored on function return type
So it's not just your static analysis program that's complaining.
You can use a different technique to illustrate your intent without making the tools unhappy.
#define CONST_RETURN
CONST_RETURN int foo();
You don't have a problem with const char * because that's declaring a pointer to constant chars, not a constant pointer.
Ignoring the const for now, foo() returns a value. You can do
int x = foo();
and assign the value returned by foo() to the variable x, in much the same way you can do
int x = 42;
to assign the value 42 to variable x.
But you cannot change the 42 ... or the value returned by foo(). Saying that the value returned from foo() cannot be changed, by applying the const keyword to the type of foo() accomplishes nothing.
Values cannot be const (or restrict, or volatile). Only objects can have type qualifiers.
Contrast with
const char *foo();
In this case, foo() returns a pointer to an object. The object pointed to by the value returned can be qualified const.
The int is returned by copy. It may be a copy of a const, but when it is assigned to something else, that something by virtue of the fact that it was assignable, cannot by definition be a const.
The keyword const has specific semantics within the language, whereas here you are misusing it as essentially a comment. Rather than adding clarity, it rather suggests a misunderstanding of the language semantics.
const int foo() is very different from const char* foo(). const char* foo() returns an array (usually a string) whose content is not allowed to change. Think about the difference between:
const char* a = "Hello World";
and
const int b = 1;
a is still a variable and can be assigned to other strings that can't change whereas b is not a variable. So
const char* foo();
const char* a = "Hello World\n";
a = foo();
is allowed but
const int bar();
const int b = 0;
b = bar();
is not allowed, even with the const declaration of bar().
Yes. I would advise writing code "explicitly", because it makes it clear to anyone (including yourself) when reading the code what you meant. You are writing code for other programmers to read, not to please the whims of the compiler and static analysis tools!
(However, you do have to be careful that any such "unnecessary code" does not cause different code to be generated!)
Some examples of explicit coding improving readability/maintainability:
I place brackets around portions of arithmetic expressions to explicitly specify what I want to happen. This makes it clear to any reader what I meant, and saves me having to worry about (or make ay mistakes with) precedence rules:
int a = b + c * d / e + f; // Hard to read- need to know precedence
int a = b + ((c * d) / e) + f; // Easy to read- clear explicit calculations
In C++, if you override a virtual function, then in the derived class you can declare it without mentioning "virtual" at all. Anyone reading the code can't tell that it's a virtual function, which can be disastrously misleading! However you can safely use the virtual keyword: virtual int MyFunc() and this makes it clear to anyone reading your class header that this method is virtual. (This "C++ syntax bug" is fixed in C# by requiring the use of the "override" keyword in this case - more proof if anyone needed it that missing out the "unnecessary virtual" is a really bad idea)
These are both clear examples where adding "unnecessary" code will make the code more readable and less prone to bugs.

Resources