I know that when a variable declaration precedes with register keyword compiler may put the variable in CPU's register for faster access. Same way I know that compiler can put const variable in ROM because const variable's value won't change throughout the execution of program.I know also that register specifier is a request to the implementation to put variable in CPU register. But where the variable will be stored if it is marked with both const & register?
Consider following program:
#include <stdio.h>
int main()
{
register const int a=3;
printf("%d",a);
return 0;
}
In this case where the variable gets stored? In the CPU register or on the stack(if compiler ignores the register request) or in the ROM if compiler optimizes it.
I don't actually know what any individual compiler does in this situation, but from logic, and given that register is more of a suggestion, and the compiler is permitted to ignore it as far as the standard goes, I'd say there are three likely outcomes:
As constants are usually pretty efficient, and can often be encoded as part of the instruction or optimized out, and therefore might not even need to be loaded from the data section into a register explicitly, it might just ignore the register keyword completely and treat it as just const.
If there is any code generation step that needs to decide which values to put in a register and which elsewhere, and a is one of these values, the compiler might take into account that you declared it as register and prefer that.
(And this may just be a variation on #2) The compiler may decide that you had a reason to specify register here and always force a into a register when it can. Worst case, this could run counter to how the optimizer would usually assign your code to registers though, and could result in sub-optimal code. Or if you really know what you're doing, it might work around an optimizer bug.
First when you declare a variable as const, the compiler will never put it in ROM, because ... neither the compiler, nor the linker, nor later loader can write anything in ROM ! It can only put it in read-only segments that will still reside in RAM even if any write access at run time will cause an error.
Then to answer more precisely your question, the compiler may always do what it wants.
when you declare a variable const, the compiler should throw an error if it detects a change and can put it in a read-only segment
when you declare a variable register, the compiler should throw en error if it detects an attempt to take its address, and can try to keep it in register.
The only thing that is explicitely required is that a compiler correctly processes correct code. It is requested to throw an error if it cannot compile some code, but it is allowed to accept incorrect code : that may be called extensions or special features. For example a compiler is free to declare that it fully ignores register declaration and allows taking the address of a register variable but it must at least issue a warning [edit see below for details]. Simply it must not choke on correct register (or const usage).
And it can make use of register and const declaration for its optimisations but is perfectly free to ignore them. For example the following code :
const int a = 5;
const int *b = (int *) &a;
*b = 4;
leads to Undefined Behaviour. It is implementation dependant if after that :
a = 5
a = 4
the program crashed
the computer was burned to fire (but this one should be uncommon :-) )
...
EDIT :
JensGustedt noted in comment that C language specification contains in paragraph 6.5.3.2 Address and indirection operators this constraint clause :
The operand of the unary & operator shall ..., or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier. (emphasize mine)
As it in a constraint clause, paragraph 5.1.1.3 Diagnostics of same specification requires that A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint.
So a conforming C compiler shall at least issue a warning if programmer tries to take the address of a register variable.
Related
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.
volatile int vfoo = 0;
void func()
{
int bar;
do
{
bar = vfoo; // L.7
}while(bar!=1);
return;
}
This code busy-waits for the variable to turn to 1. If on first pass vfoo is not set to 1, will I get stuck inside.
This code compiles without warning.
What does the standard say about this?
vfoo is declared as volatile. Therefore, read to this variable should not be optimized.
However, bar is not volatile qualified. Is the compiler allowed to optimize the write to this bar? .i.e. the compiler would do a read access to vfoo, and is allowed to discard this value and not assign it to bar (at L.7).
If this is a special case where the standard has something to say, can you please include the clause and interpret the standard's lawyer talk?
What the standard has to say about this includes:
5.1.2.3 Program execution
¶2 Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.
¶4 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).
¶6 The least requirements on a conforming implementation are:
Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.
...
The takeaway from ¶2 in particular should be that accessing a volatile object is no different from something like calling printf - it can't be elided because it has a side effect. Imagine your program with bar = vfoo; replaced by bar = printf("hello\n");
volatile variable has to be read on any access. In your code snippet that read cannot be optimized out. The compiler knows that bar might be affected by the side effect. So the condition will be checked correctly.
https://godbolt.org/z/nFd9BB
However, bar is not volatile qualified.
Variable bar is used to hold a value. Do you care about the value stored in it, or do you care about that variable being represented exactly according to the ABI?
Volatile would guarantee you the latter. Your program depends on the former.
Is the compiler allowed to optimize the write to this bar?
Of course. Why would you possibly care whether the value read was really written to a memory location allocated to the variable on the stack?
All you specified was that the value read was tested as an exit condition:
bar = ...
}while(bar!=1);
.i.e. the compiler would do a read access to vfoo, and is allowed to
discard this value and not assign it to bar (at L.7).
Of course not!
The compiler needs to hold the value obtained by the volatile read enough time to be able to compare it to 1. But no more time, as you don't ever use bar again latter.
It may be that a strange CPU as a EQ1 ("equal to 1") flag in the condition register, that is set whenever a value equal to 1 is loaded. Then the compiler would not even store temporarily the read value and just EQ1 condition test.
Under your hypothesis that compilers can discard variable values for all non volatile variables, non volatile objects would have almost no possible uses.
The C register keyword gives the compiler a hint to prefer storing a variable in a register rather than, say, on the stack. A compiler may ignore it if it likes. I understand that it's mostly-useless these days when you compile with optimization turned on, but is it entirely useless?
More specifically: For any combination of { gcc, clang, msvc } x { -Og, -O, -O2, -O3 }: Is register ignored when deciding whether to actually assign a register? And if not, are there cases in which it's useful enough to bother using it?
Notes:
I am not asking whether it the keyword any effect; of course it does - it prevents you from using the address of that variable; and if you don't optimize at all, it will make the difference between register assignment or memory assignment for your variable.
Answers for just one compiler / some of the above combinations are very welcome.
For GCC, register has had no effect on code generation at all, not even a hint, at all optimization levels, for all supported CPU architectures, for over a decade.
The reasons for this are largely historical. GCC 2.95 and older had two register allocators, one ("stupid") used when not optimizing, and one ("local, global, reload") used when optimizing. The "stupid" allocator did try to honor register, but the "local, global, reload" allocator completely ignored it. (I don't know what the original rationale for that design decision was; you'd have to ask Richard Kenner.) In version 3.0, the "stupid" allocator was scrapped in favor of adding a fast-and-sloppy mode to "local, global, reload". Nobody bothered to write the code to make that mode pay attention to register, so it doesn't.
As of this writing, the GCC devs are in the process of replacing "local, global, reload" with a new allocator called "IRA and LRA", but it, too, completely ignores register.
However, the (C-only) rule that you cannot take the address of a register variable is still enforced, and the keyword is used by the explicit register variable extension, which allows you to dedicate a specific register to a variable; this can be useful in programs that use a lot of inline assembly.
C Standard says:
(c11, 6.7.1p6) "A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible. The extent to which such suggestions are effective is implementation-defined."
These suggestions being implementation-defined means the implementation must define the choices being made ((c11, J.3.8 Hints) "The extent to which suggestions made by using the register storage-class specifier are effective (6.7.1)").
Here is what the documentation of some popular C compilers says.
For gcc (source):
The register specifier affects code generation only in these ways:
When used as part of the register variable extension, see Explicit Register Variables.
When -O0 is in use, the compiler allocates distinct stack memory for all variables that do not have the register storage-class
specifier; if register is specified, the variable may have a
shorter lifespan than the code would indicate and may never be
placed in memory.
On some rare x86 targets, setjmp doesn’t save the registers in all circumstances. In those cases, GCC doesn’t allocate any
variables in registers unless they are marked register.
For IAR compiler for ARM (source):
Honoring the register keyword (6.7.1)
User requests for register variables are not honored
If an object of automatic storage duration never has its address taken, a compiler may safely assume that its value can only be observed or modified by code which uses it directly. In the absence of the register keyword, a compiler which generates code in single-pass fashion would have no way of knowing, given...
void test(int *somePointer)
{
int i;
for (int i=0; i<10; i+=2)
{
somePointer[i] = -1;
somePointer[i+1] = 2;
whether the write to somePointer[i] might possibly write i. If it could, then the compiler would be required to reload i when evaluating somePointer[i+1]. Applying the register keyword to i would allow even a single-pass compiler to avoid the reload because it would be entitled to assume that no valid pointer could hold a value derived from the address of i, and consequently there was no way that writing somePointer[i] could affect i.
The register keyword could be useful, even today, if it were not interpreted as imposing a constraint that the address of an object cannot be exposed to anything, but rather as inviting compilers to assume that no pointer derived from an object's address will be used outside the immediate context where the address was taken, and within contexts where the address is taken the object will be accessed only using pointers derived from address. Unfortunately, the only situations the Standard permits register qualifiers are those where an object's address is never neither used nor exported to outside code in any fashion--i.e. cases which a multi-pass compiler could identify by itself without need for the qualifier.
The register keyword could be useful, even with modern compilers, if it invited compilers to--at their leisure--treat any context where a register-qualified object's address is taken (e.g. get_integer(&i);) using the pattern:
{
int temp = i;
get_integer(&temp);
i = temp;
}
and to assume that a register-qualified object of external scope will only be accessed in contexts which either explicitly access the object or take its address. At present, compilers have very limited ability to cache global variables in registers across pointer accesses involving the same types; the register keyword could help with that except that compilers are required to treat as constraint violations all the situations where it could be useful.
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.
Consider the following:
volatile uint32_t i;
How do I know if gcc did or did not treat i as volatile? It would be declared as such because no nearby code is going to modify it, and modification of it is likely due to some interrupt.
I am not the world's worst assembly programmer, but I play one on TV. Can someone help me to understand how it would differ?
If you take the following stupid code:
#include <stdio.h>
#include <inttypes.h>
volatile uint32_t i;
int main(void)
{
if (i == 64738)
return 0;
else
return 1;
}
Compile it to object format and disassemble it via objdump, then do the same after removing 'volatile', there is no difference (according to diff). Is the volatile declaration just too close to where its checked or modified or should I just always use some atomic type when declaring something volatile? Do some optimization flags influence this?
Note, my stupid sample does not fully match my question, I realize this. I'm only trying to find out if gcc did or did not treat the variable as volatile, so I'm studying small dumps to try to find the difference.
Many compilers in some situations don't treat volatile the way they should. See this paper if you deal much with volatiles to avoid nasty surprises: Volatiles are Miscompiled, and What to Do about It. It also contains the pretty good description of the volatile backed with the quotations from the standard.
To be 100% sure, and for such a simple example check out the assembly output.
Try setting the variable outside a loop and reading it inside the loop. In a non-volatile case, the compiler might (or might not) shove it into a register or make it a compile time constant or something before the loop, since it "knows" it's not going to change, whereas if it's volatile it will read it from the variable space every time through the loop.
Basically, when you declare something as volatile, you're telling the compiler not to make certain optimizations. If it decided not to make those optimizations, you don't know that it didn't do them because it was declared volatile, or just that it decided it needed those registers for something else, or it didn't notice that it could turn it into a compile time constant.
As far as I know, volatile helps the optimizer. For example, if your code looked like this:
int foo() {
int x = 0;
while (x);
return 42;
}
The "while" loop would be optimized out of the binary.
But if you define 'x' as being volatile (ie, volatile int x;), then the compiler will leave the loop alone.
Your little sample is inadequate to show anything. The difference between a volatile variable and one that isn't is that each load or store in the code has to generate precisely one load or store in the executable for a volatile variable, whereas the compiler is free to optimize away loads or stores of non-volatile variables. If you're getting one load of i in your sample, that's what I'd expect for volatile and non-volatile.
To show a difference, you're going to have to have redundant loads and/or stores. Try something like
int i = 5;
int j = i + 2;
i = 5;
i = 5;
printf("%d %d\n", i, j);
changing i between non-volatile and volatile. You may have to enable some level of optimization to see the difference.
The code there has three stores and two loads of i, which can be optimized away to one store and probably one load if i is not volatile. If i is declared volatile, all stores and loads should show up in the object code in order, no matter what the optimization. If they don't, you've got a compiler bug.
It should always treat it as volatile.
The reason the code is the same is that volatile just instructs the compiler to load the variable from memory each time it accesses it. Even with optimization on, the compiler still needs to load i from memory once in the code you've written, because it can't infer the value of i at compile time. If you access it repeatedly, you'll see a difference.
Any modern compiler has multiple stages. One of the fairly easy yet interesting questions is whether the declaration of the variable itself was parsed correctly. This is easy because the C++ name mangling should differ depending on the volatile-ness. Hence, if you compile twice, once with volatile defined away, the symbol tables should differ slightly.
Read the standard before you misquote or downvote. Here's a quote from n2798:
7.1.6.1 The cv-qualifiers
7 Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C.
The keyword volatile acts as a hint. Much like the register keyword. However, volatile asks the compiler to keep all its optimizations at bay. This way, it won't keep a copy of the variable in a register or a cache (to optimize speed of access) but rather fetch it from the memory everytime you request for it.
Since there is so much of confusion: some more. The C99 standard does in fact say that a volatile qualified object must be looked up every time it is read and so on as others have noted. But, there is also another section that says that what constitutes a volatile access is implementation defined. So, a compiler, which knows the hardware inside out, will know, for example, when you have an automatic volatile qualified variable and whose address is never taken, that it will not be put in a sensitive region of memory and will almost certainly ignore the hint and optimize it away.
This keyword finds usage in setjmp and longjmp type of error handling. The only thing you have to bear in mind is that: You supply the volatile keyword when you think the variable may change. That is, you could take an ordinary object and manage with a few casts.
Another thing to keep in mind is the definition of what constitutes a volatile access is left by standard to the implementation.
If you really wanted different assembly compile with optimization