Reputation: 110382
Let's take the following two function:
#include<stdio.h>
void my_print1(char* str) {
// str = "OK!";
printf("%s\n", str);
}
void my_print2(char* const str) {
// str = "OK!";
printf("%s\n", str);
}
They both produce the same assembly
:
How then is the const
-ness enforced here? For example, if I un-comment str = "OK!;
it will of course work in the first function call but not the second (error: assignment of read-only parameter ‘str’
).
Is the const
-ness of a local variable just a compiler construct, and it is responsible for checking that, or how does it work if the assembly for the two functions is the same? Note: this is C only, not C++ (as I think they treat const different).
Upvotes: 1
Views: 448
Reputation: 6669
The compiler enforces const
by refusing to generate non-compliant code. If the my_print2
source had attempted to modify str
, the compiler would have issued an error message.
With respect to your code however:
void my_print2(char* const str)...
It's kind of pointless as it can only limit what the function can do with the value of the pointer itself, not what it can do to memory it points to, so:
void my_print2(char* const str)
{
str++; // Not allowed, compile time error.
*str = 'A'; // Okay.
}
Functions that do not need to modify the content of what is pointed to, should be declared as const <type> *
to give callers confidence that your function, print in this case, won't change their data:
void my_print3(const char* str)
{
str++; // Okay
*str = 'A'; // Not allowed, compile time error.
}
void my_print4(char const* str)
{
str++; // Okay
*str = 'A'; // Not allowed, compile time error.
}
Upvotes: 0
Reputation: 58518
Correct, on most implementations it's just a compiler construct.
On a typical mainstream OS implementation, there is a way to place const
objects having static
storage duration in memory that is actually write-protected by the CPU's memory-management unit (MMU), e.g. a .text
or .rodata
section. Then attempts to write it, if not prevented at compile time, will cause a trap at runtime. But hardware write protection applies to large blocks of memory (e.g. whole pages). There is no good way to do this with auto
objects, such as local variables or function parameters, which live in stack memory or in registers. On the stack, since they are mixed in with non-const
variables, hardware write protection is not fine-grained enough to apply to them, and in any case would be very expensive to be continually changing (it needs a call to the operating system). And registers on most machines cannot be made read-only at all.
Since there is no good way to protect them at runtime, compilers often generate the exact same code for const
auto objects as for non-const
.
You might see differences in some cases, since const
informs the compiler that the object's value is not supposed to change, and therefore the compiler can assume that it does not. For instance, if you pass a pointer to a non-const
object to another function, the compiler has to assume that the value of the object may have been changed, and will reload it from memory after each function call. But a const
object may have its value cached in a register across the functionn call, or just optimized into an immediate constant if possible.
Upvotes: 4
Reputation: 781907
The const
qualifier on function parameters and other local variables normally has no effect on the generated code. It just tells the compiler to prevent assigning to the variable.
Theoretically, it could generate code that prevents modifying the variable through other means. E.g. if you had
void my_print2(char* const str) {
*(char *)&str = "OK!";
printf("%s\n", str);
}
The assignment causes undefined behavior, but won't cause an error (although the compiler might warn about casting away constness). But the compiler could theoretically store str
in memory that's marked read-only; in that case, the assignment would cause a segmentation fault. This would not normally be done for function parameters because it's difficult to reconcile that with using the stack for automatic data. (Nate Eldredge's answer explains this better.)
Upvotes: 3