In the following:
struct adt { void * A; };
int new_adt(const void * const A)
{
struct adt * r = malloc(sizeof(struct adt));
r->A = A;
}
I get:
warning: assignment discards qualifiers from pointer target type
I know I can use
memcpy(&(r->A), &A, sizeof(void *));
to workaround it, but I must ask: Is there any alternative?
By using const void * const I pretend to say that no changes will be made to the input. Also, now that I think of it, const void * would suffice, wouldn't it? (Since I can't change the pointer so that it affects the caller)
Thanks for taking the time to read.
By using const void * const I pretend to say that no changes will be made to the input.
You have not pretended to say that no changes will be made to the input, you have explicitly told the compiler that you have guaranteed that no changes will be made to the input.
You MUST NOT do what you are doing.
If you never want to modify A through its pointer from adt, then you should make that pointer const as well, i.e.:
struct adt {
const void * A;
};
That will make the error go away.
If you do want to modify A through adt, then new_adt should take a non-const pointer.
Edit: A more general note, which may help:
The const keyword, in general, applies to the type immediately to its left. However, if there is no type to its left, it will apply to the type to the right. So:
const int * A is the same as int const * A (the const applies to the int, not to the pointer), but in int * const A, the const applies to the pointer, not to the int.
There is a more comprehensive explanation on Wikipedia: const-correctness. The 'Pointers and References' section of that page includes an example which covers the various combinations of const and non-const that you can apply to a pointer.
You can cast the const away:
r->A = (void *) A;
The issue, though, is less about how to avoid the warning and more about what you're trying to do. The compiler is warning you because you're telling the compiler that "A" is not writable, but you're trying to store it in a location that defines it as writable. That's generally not OK, semantically.
Imagine that "A" points to a location in your binaries data section; trying to write to it, after casting the const away, will most probably cause a segfault.
So, really, think about what you're trying to do more closely before trying to work around the compiler warning. They're warnings for a good reason.
Related
A function declared
void f(const char * const p) { ... }
means that it takes a constant pointer to a constant character. But, with the variable p scoped only within the function itself and its usage hidden from the callee, does it matter if the second const is there?
In other words, wouldn't the following be semantically identical to the first from the perspective of the callee?
void f(const char *p) { ... }
The first const indicates that you can't change the data is pointing to, the second indicates that this pointer can't be overwritten.
So, for a caller of this function, it doesn't matter.
For the implementation of the function, it can be useful, though it will only have effect locally.
The second const (the one after the *) doesn't matter from the callee point of view.
But it does matter from the point of view of the function body.
The second const makes sure that you can't make the pointer change its value (i.e. point to a different memory location).
It's comparable to declaring a simple primitive parameter as const, like in void f(const int value) {}
Yes. You tell the compiler that you won't modify p in that function. This allows the compiler certain optimizations, e.g. if p is already in a register, there's no need to save it and no need to allocate a new register.
It also causes the compiler to issue a diagnostic should you attempt to modify p, eg. ++p or p = ... because that violates the promise you made.
Yes, I believe so. The additional const here only means that in the implementation of f, the implementer is not allowed to reassign p to point to some other character or C-style string.
My question is, if it is correct to define both:
typedef void* Elem;
typedef const void* const constElem;
If I know that I would work with const and non const generic elements, for example for the copyElem function as a parameter, I would prefer to get it as const, for the const correctness, is this practical?
I don't see how there is a matter of correctness here, except inasmuch as yes, both typedefs you present are syntactically correct, and it is possible that a program would have use for both types.
As a matter of style, however, it is poor form to hide pointer nature behind a typedef. It very easily becomes confusing.
It is also a bit questionable to typedef anything as void * -- it provides no type safety of any significance, and not much semantic assistance either. If you really want to accept a pointer to anything, then just say void *. If, on the other hand, you want to hide the details of a struct type, then just declare the structure type as an incomplete type, and leave it that way:
struct Elem;
Optionally, typedef that for convenience:
typedef struct Elem Elem;
Personally, and again as a matter of style, I would prefer to see the const keyword than to see a typedef that rolls in the const, no matter how clearly designated.
Note also that all questions of style aside, this particular typedef ...
typedef const void* const constElem;
... seems of rather narrow usefulness. It designates a pointer whose value cannot be changed and that points to an object that also cannot be changed. A non-const pointer to a const object is much more often what you want. Note, too, that the uncertainty over what constElem should mean is one consequence of rolling up pointer nature inside the Elem typedef.
const void *const doesn't buy you much, unless it is used as the type of a function parameter:
void foo(const void *const e)
{
e = NULL; // compile-time error because of the second const
char *s = e; // compile-time error because of the first const
const char *t = e; // OK
}
...
char x[] = "test";
foo(x); // you can be confident that foo will not modify the contents
For regular usage it is impractical because the first const says that the dereferenced value cannot be modified, but void pointers cannot be dereferenced anyway. The second const essentially doesn't allow you to reassign the pointer once it is initialised.
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.
I got a bunch of code, that I should analyze and prepare for import it to a new project. Often there are the following patterns:
typedef struct t_Substruct
{
/* some elements */
} ts;
typedef struct t_Superstruct
{
/* some elements */
ts substruct;
/* some more elements */
} tS;
void funct1(const tS * const i_pS, tS * const o_pS)
{ /* do some complicated calculations and transformations */ }
void funct2(const ts * const i_ps, tS * const o_pS)
{ /* do some complicated calculations and transformations */ }
void funct3(const tS * const i_ps, ts * const o_ps)
{ /* do some complicated calculations and transformations */ }
In general there is reading from the i_ parameters and writing to the o_ parameters. Now there might be calls like:
void some_funct()
{
tS my_struct = {0};
/* do some stuff */
funct1(&my_struct,&my_struct);
funct2(&my_struct.substruct, &my_struct);
funct3(&my_struct, &my_struct.substruct);
}
Im not sure about the possible pitfalls to such functions and calling context:
Are such declarations or calls in context of const correctness allowed with regards to language constraints and/or undefined behavior?
Is it allowed to change one object, that is referenced protected and not protected in the same function?
I know there are some problems with accessing / modifying the same variable multiple times between, sequence points (although I am not perfectly sure if I understand the sequence point thing totally). Does this or similar issues apply here, and in which way?
If not undefined behavior, is there any other typical problem which reduces portability in the above situation?
If there are problems, what would be a good (safe and if possible with as little overhead as possible) general pattern to allow those calls, so that such issues might not happen every other line?
I have to implement in C90, but if there are issues in porting to other C incarnations, regarding the above, this is also important for me.
Thank you in advance.
There are two different sides related to const with a pointer S* p.
Is it allowed to change the pointer? Example: p=5;
Is it allowed to change the object pointed to? Example: p->x = 5;
These are the four possibilities:
T* p: both changes allowed
const T* p: object can not be changed
T* const p: pointer can not be changed
const T* const p: neither object nor pointer can be changed
In your example void funct1(const tS * const i_pS, tS * const o_pS) this means the following:
You are not allowed to change the pointers i_pS and o_pS.
You are not allowed to change the object pointed to by i_pS.
You are allowed to change the object pointed to by o_pS.
The first condition looks rather pointless, so probably this
void funct1(const tS* i_pS, tS* o_pS)
is more readable.
Regarding the second and third case where you have two pointers which point to the same part of an object: Be careful that you do not make wrong assumptions in the code, for example that the object pointed to by the const pointer is actually not changing.
Remember, a const pointer does never mean the object is not changing, only that you are not allowed to change it via that pointer.
Example for problematic code:
void foo(const S* a, S* b) {
if(a->x != 0) {
b->x = 0;
b->y = 5 / a->x; // why is a->x suddenly 0 ??
}
}
S s;
foo(&s, &s);
Regarding undefined behaviour and sequence points. I would advice to read this answer: Undefined behavior and sequence points
So for example the expression i = a->x + (b->x)++; is definitely undefined behavior if a and b point to the same object.
A function void funct1(const tS* i_ps, tS* o_pS) which is called as funct1(&my_struct, &my_struct); is an open door to confusion and errors.
The C library also knows that problem. Consider for example memcpy and memmove.
So I would advice to build your functions such that you can be sure that no undefined behavior can occur. The most drastic measure would be to make a complete copy of the input struct. This has overhead, but in your specific case perhaps it is enough to copy only some small part of the input argument.
If the overhead is too big, specifically state in the function documentation that it is not allowed to give the same object as input and output. Then, if possible and necessary, create a second function with the necessary overhead to handle the case where input and output are the same.
This call is invalid. For example:
funct1(&my_struct.substruct, &my_struct.substruct);
because funct1 expects a tS * but these are ts *. You would need to get a cast to get this to compile. The code would then work (because there is actually a tS at the pointed-to location) but it is strange to say the least, you should just change it to &my_struct instead of adding the cast.
Also, I beg you to use a different naming convention than ts versus tS.
As Danvil says, it's important that your code takes account of the fact that the two pointers may be pointing to parts of the same object.
As a matter of style, I don't like the "top level const". It makes the function header harder to read, and you have to take some time to work out what is const and what isn't.
I was recently making some adjustments to code wherein I had to change a formal parameter in a function. Originally, the parameter was similar to the following (note, the structure was typedef'd earlier):
static MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
The change was made because I could define and initialize my_special_structure before compile time and myFunction never changed the value of it. This led to the following change:
static const MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (const MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
I also noticed that when I ran Lint on my program that there were several Info 818's referencing a number of different functions. The info stated that "Pointer parameter 'x' (line 253) could be declared as pointing to const".
Now, I have two questions in regards to the above. First, in regards to the above code, since neither the pointer nor the variables within MySpecialStructure is changed within the function, is it beneficial to declare the pointer as constant as well? e.g. -
int myFunction (const MySpecialStructure * const p_structure, unsigned char useful_char)
My second question is in regards to the Lint information. Are there any benefits or drawbacks to declaring pointers as a constant formal parameter if the function is not changing its value... even if what you are passing to the function is never declared as a constant? e.g. -
static unsigned char my_char;
static unsigned char * p_my_char;
p_my_char = &my_char;
int myFunction (const unsigned char * p_char)
{
...
}
Thanks for your help!
Edited for clarification -
What are the advantages of declaring a pointer to const or a const pointer to const- as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
What are the advantages of declaring a pointer as a const - as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
I assumed you meant a pointer to const.
By have a pointer to const as a parameter, the advantage is you document the API by telling the programmer your function does not modify the object pointed by the pointer.
For example look at memcpy prototype:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
It tells the programmer the object pointed to by s2 will not be modified through memcpy call.
It also provides compiler enforced documentation as the implementation will issue a diagnostic if you modify a pointee from a pointer to const.
const also allows to indicate users of your function that you won't modify this parameter behind their back
If you declare a formal parameter as const, the compiler can check that your code does not attempt to modify that parameter, yielding better software quality.
Const correctness is a wonderful thing. For one, it lets the compiler help keep you from making mistakes. An obvious simple case is assigning when you meant to compare. In that instance, if the pointer is const, the compiler will give you an error. Google 'const correctness' and you'll find many resources on the benefits of it.
For your first question, if you are damn sure of not modifying either the pointer or the variable it points to, you can by all means go ahead and make both of them constant!
Now, for your Qn as to why declare a formal pointer parameter as const even though the passed pointer is not constant, A typical use case is library function printf(). printf is supposed to accept const char * but the compiler doesn't complain even if you pass a char* to it. In such a case, it makes sense that printf() doesn't not build upon the user's mistake and alter user's data inadvertantly! Its like printf() clearly telling- Whether you pass a const char * or char*, dont worry, I still wont modify your data!
For your second question, const pointers find excellent application in the embedded world where we generally write to a memory address directly. Here is the detailed explanation
Well, what are the advantages of declaring anything as a const while you have the option to not to do so? After all, if you don't touch it, it doesn't matter if it's const or not. This provides some safety checks that the compiler can do for you, and it gives some information of the function interface. For example, you can safely pass a string literal to a function that expects a const char *, but you need to be careful if the parameter is declared as just a char *.