'const' in C language may be redundant? - c

I have been confusing with const in the C language. I think if no const conception, all the programme existed in the world also could run smoothly.so Can anyone help me and give me some explanation.

Yes, if you removed const, most1 C code would continue to work as it does today.
However, const really exists to save the programmer from himself. The const modifier on a function parameter says: "this function promises to not modify the object this points to." So if you forget, and try to modify the object, the compiler will stop you.
1 - I say "most" because const can also have a runtime effect. Statically-allocated objects marked const will typically be placed in a read-only section in the program image, and this data is marked as read-only when the program is loaded. So if you were to cast away the const and try to write to this object, your program will segfault. The crash here is desired. Because it prevents your program from running with invalid assumptions about its data.

No, is not redundant at all. The qualifier const is usually applied to the declaration of any variable to specify that its value will not be changed during the program execution (Which depends upon where const variables are stored, we may change value of const variable by using pointer). If you have ever programmed in Java, is similar to an static variable.
You can read more about const here: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html

const will make the assembly code into an absolute number value. It will not be a register or memory value and can't be modified by the code of course. It makes for fast program operation because it doesn't load the value from memory or a register.
However, most optimized coding already does this in assembly when it realizes the value isn't changed.
John

Related

difference between static const int vs const int

const int a = 100;
int *p = &a;
*p = 99;
printf("value %d", a);
Above code compiles and I am able to update its value via pointer but code below didn't output anything.
static const int a = 100;
int *p = &a;
*p = 99;
printf("value %d", a);
Can anyone explain this thing.
Both code snippets are invalid C. During initialization/assignment, there's a requirement that "the type pointed to by the left has all the qualifiers of the type pointed to
by the right" (c17 6.5.16.1). This means we can't assign a const int* to an int*.
"Above code compiles" Well, it doesn't - it does not compile cleanly. See What must a C compiler do when it finds an error?.
I would recommend you to block invalid C from compiling without errors by using (on gcc, clang, icc) -std=c11 -pedantic-errors.
Since the code is invalid C, it's undefined behavior and why it has a certain behavior is anyone's guess. Speculating about why you get one particular output from one case of undefined behavior to another isn't very meaningful. What is undefined behavior and how does it work? Instead focus on writing valid C code without bugs.
There are several things going on here:
const does not mean "Put this variable in read-only memory or otherwise guarantee that any attempt to modify it will definitively result in an error message."
What const does mean is "I promise not to try to modify this variable." (But you broke that promise in both code fragments.)
Attempting to modify a const-qualified variable (i.e., breaking your promise) yields undefined behavior, which means that anything can happen, meaning that it might do what you want, or it might give you an error, or it might do what you don't want, or it might do something totally different.
Compilers don't always complain about const violations. (Though a good compiler should really have complained about the ones here.)
Some compilers are selective in their complaints. Sometimes you have to ask the compiler to warn about iffy things you've done.
Some programmers are careless about ignoring warnings. Did your compiler give you any warnings when you compiled this?
The compiler should complain in both cases when you store the address of a const int into p, a pointer to modifiable int.
In the first snippet, a is defined as a local variable with automatic storage: although you define it as const, the processor does not prevent storing a value into it via a pointer. The behavior is undefined, but consistent with your expectations (a is assigned the value 99 and this value is printed, but the compiler could have assumed that the value of a cannot be changed, hence could have passed 100 directly to printf without reading the value of a).
In the second snippet, a is a global variable only accessible from within the current scope, but the compiler can place it in a read-only location, causing undefined behavior when you attempt to modify its value via the pointer. The program may terminate before evaluating the printf() statement. This is consistent with your observations.
Briefly, modifying const-qualified static objects causes a trap and modifying a const-qualified automatic object does not because programs are able to place static objects in protected memory but automatic objects must be kept in writeable memory.
In common C implementations, a const-qualified static object is placed in a section of the program data that is marked read-only after it is loaded into memory. Attempting to modify this memory causes the processor to execute a trap, which results in the operating system terminating execution of the program.
In contrast, an object with automatic storage duration (one defined inside a function without static or other storage duration) cannot easily be put in a read-only program section. This is because automatic objects need to be allocated, initialized, and released during program execution, as the functions they are defined in are called and returned. So even though the object may be defined as const for the purposes of the C code, the program needs to be able to modify the memory actually used for it.
To achieve this, common C implementations put automatic objects on the hardware stack, and no attempt is made to mark the memory read-only. Then, if the program mistakenly attempts to modify a const-qualified automatic object, the hardware does not prevent it.
The C standard requires that the compiler issue a diagnostic message for the statement int *p = &a;, since it attempts to initialize a pointer to non-const with the address of a const-qualified type. When you ignore that message and execute the program anyway, the behavior is not defined by the C standard.
Also see this answer for explanation of why the program may behave as though a is not changed even after *p = 99; executes without trapping.
6.7.3 Type qualifiers
...
6 If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is
made to refer to an object defined with a volatile-qualified type through use of an lvalue
with non-volatile-qualified type, the behavior is undefined.133)
133) This applies to those objects that behave as if they were defined with qualified types, even if they are
never actually defined as objects in the program (such as an object at a memory-mapped input/output
address).
C 2011 Online Draft
If you declare a as const, you're making a promise to the compiler that the value of a should not change during its lifetime; if you try to assign a new value to a directly the compiler should at least issue a diagnostic. However, by trying to change a through a non-const pointer p you're breaking that promise, but you're doing it in such a way that the compiler can't necessarily detect it.
The resulting behavior is undefined - neither the compiler nor the runtime environment are required to handle the situation in any particular way. The code may work as expected, it may crash outright, it may appear to do nothing, it may corrupt other data. const-ness may be handled in different ways depending on the compiler, the platform, and the code.
The use of static changes how a is stored, and the interaction of static and const is likely what's leading to the different behavior. The static version of a is likely being stored in a different memory segment which may be read-only.

Why must be structure initialized in rust?

In C I can use a struct that has not yet been initialized. I tried this code in Rust:
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main(){
let mut user1: User;
user1.active = false;
}
But it produced a compilation error:
error[E0381]: assign to part of possibly-uninitialized variable: `user1`
--> src/main.rs:10:5
|
10 | user1.active = false;
| ^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `user1`
Why is this allowed in C but an error in Rust?
All values in Rust must have an initialized value if they are to be safely accessed.
This is because operations using uninitialized values have undefined behaviour. What this may result in is the compiler accidentally miscompiling your code.
Avoiding miscompilation is one of the prime goals of Rust; including other forms of undefined behaviour such as data races, dereferencing an invalid pointer, or mutating data that other code assumes to not change. Read more here.
In C, you can access those values; thereby permitting the compiler to miscompile your code since you've broken contract. In Rust however, you aren't allowed to do that.
In some languages, such as C# you replace uninitialized values with null. We have a similar concept: Options, which are either Some(value) or there is None.
Please note that if the compiler miscompiles your code due to undefined behaviour associated with unsound operations, it's not the compiler's fault. It's not trying to look for this either; it is just trying to optimize your code. If I give you a baseball bat and you used it to smack your head, then you'd be misusing it, it wouldn't be my fault, as a designer, since I couldn't foresee you misusing it.
There are ways to do what you can do in C though. These are unsafe and are strongly discouraged for regular operations though, so please try your hardest to look for another solution before jumping into unnecessary unsafe and possibly unsound behaviour.
Use std::mem::MaybeUninit and read the Rust nomicon before dabbling in unsafe.
As Optimistic Peach already said, this is mainly just the way Rust works. Everything needs to be initialized in Rust. It's the same with every other variable as well.
But the reason why Rust does it that way is not a problem with the compiler. As you know from C, the compiler there can compile the code without problems, even if variables don't get initialized. The problem is, that if you just define a variable without initializing it, the variable can be accessed and the value will be whatever is already in the memory location the variable is stored at.
Rust tries to be a language, that is very safe. Access to uninitialized memory has been often the cause of bugs, so it does want to prevent this. The designers could have chosen to use some default value to be used, when no default is given in the program code, but they decided to always require explicit default values.—That's more or less just a design choice they did.
Probably a reason for this design choice is that in Rust there are several types, where there are no obvious default values. In other languages as in C# you have the null value that can be assigned to all references. In Rust you can have something similar to null by using the Option<T> as a type (instead of just T) and assign the None value. But this only works if the programmer decided to use Option<T> instead of just T. What could be the default value for a variable of type std::fs::File if there is no null in Rust and the programmer didn't define an initial value?

Can const variables be modified from elsewhere not known at compile time

If const is a compile time construct, it would mean that only the compiler will ensure that for example if a variable is declared as const, this variable is read only and it is not attempted to be modified by the rest of the code being compiled?
What about if a const variable is a global variable in our code, and our code links to a dynamic library at run time which attempts to write to it? , or if an ISR attempts to update it, which was not in our compiled code?
I believe the compiler can mark const variables to be loaded into the read only data section which would prevent any changing of the variable, but what if it doesn't?
Thanks
the compiler will ensure that for example if a variable is declared as const, this variable is read only and it is not attempted to be modified by the rest of the code being compiled?
Yes, as far as the compiler is able to tell. If your code attempts to write to a const-qualified variable, you will get a compiler error. If you dodge type correctness by for example casting away the const qualifier, then all bets are off.
What about if a const variable is a global variable in our code, and our code links to a dynamic library at run time which attempts to write to it? , or if an ISR attempts to update it, which was not in our compiled code?
Then it should not have been const qualified, or the compiler will make strange assumptions and generate incorrect code.
However, there exist cases where a const variable may be updated from the outside world - it could be a read-only hardware register or an EEPROM memory cell etc.
To prevent the compiler from doing strange assumptions in such special cases, you can then combine const and volatile. All variables that may be updated from an external source, such as hardware or an ISR, should therefore always be declared as volatile.

How do I find variables that should be constants in C?

So, I've got this code:
uint8_t* pbytes = pkt->iov[0].iov_base;
that creates a pointer to the start of an ethernet packet in a structure.
And I ask my friend to look at the code, and he says: "You're not modifying that, and it would be really confusing if you did, so make it const".
And this seems like a good idea, so:
const uint8_t* pbytes = pkt->iov[0].iov_base;
or even:
const uint8_t * const pbytes = pkt->iov[0].iov_base;
And now I am thinking, I bet there are loads of other places where I could have done that, and I bet the compiler is going to be better at finding them than me.
Any ideas how I ask it the question? (gcc preferred, but no problems using a different compiler or a linting tool as long as they will run on unix).
GCC has a flag to suggest beneficial attributes like const
-Wsuggest-attribute=[pure|const|noreturn|format] Warn for cases where adding an attribute may be beneficial. The attributes currently
supported are listed below.
-Wsuggest-attribute=pure
-Wsuggest-attribute=const
-Wsuggest-attribute=noreturn
Warn about functions that might be candidates for attributes pure, const or noreturn. The compiler only
warns for functions visible in other compilation units or (in the case
of pure and const) if it cannot prove that the function returns
normally. A function returns normally if it doesn’t contain an
infinite loop or return abnormally by throwing, calling abort or
trapping. This analysis requires option -fipa-pure-const, which is
enabled by default at -O and higher. Higher optimization levels
improve the accuracy of the analysis.
Src: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
const propagates. In fact it often becomes a problem and is called "const poisoning". The issue is a function like strchr() which could be called with a const pointer or with a variable one. But if it returns a const *, the string cannot be modified through the pointer, which is often what you want to do.
But if you just make your constant data const at the point immediately after you read it in / initialise it, the compiler will star throwing errors at you every time you try to pass to a non-const qualified context.

Is a C compiler obligated to always reload const value from memory?

I have a const variable in my embedded C program. It's defined and initialized with 0 in program code. It's placed in a special ROM area via linker script. One can change the content of the special area via special programming procedure, but it cannot be changed during main program execution.
The question is whether I have to declare the constant as volatile. If it's not marked as volatile, is the compiler allowed to replace all references to it with 0? Or is it obligated to load it at least once during program execution?
It looks like your variable is really a constant (i.e. doesn't change during program execution) with a value unknown to the compiler. If this is the case, you can declare it like this:
extern const int variable;
(i.e. without volatile and without an initializer) and let the linker script or other tools set up the correct value.
The compiler will then be permitted to load it and potentially leave it in a register forever, but not replace it by 0 or any other value at compile time.
If marked as volatile the compiler is obliged to load it from memory every time it needs it value.
If not marked as volatile, the compiler may load it once from memory, store it in a register, and use this register instead of loading it again.
A not-optimizing compiler may do this - but it also may, stupidly, load it every time. (As not reloading is in fact an optimization in itself.)
Optimizing compilers may notice the const and decide it can be compiled with its real, literal value; up to a point where the original constant does not appear at all in the .data section of your program. (Or maybe it does but it never gets "read".)
Since you change the value in a linker script, the compiler cannot "know" the value got changed after compiling. In that case, use volatile: the only way to tell the compiler not to trust that the value is known when compiling.

Resources