how to know the access specifier used by the compiler in c - c

Is there a way to know the access specifier used by the compiler in c.
For Example-
In the case of register variables, it all depends on the compiler to decide whether a variable's access specifier would be auto or register. Is there a way to dynamically know what access specifier is chosen by the compiler??

Our are mixing up the specification level of the language and the realization of your program in machine code. The two terms "register" here are only loosely related.
The wording of the keyword register is just confusing, a misnomer. register only implies that you are not allowed to take the address of such a variable. Whether or not your compiler realizes a variable on the stack and addresses it directly or stores it in a CPU register is nothing stable that you can rely upon. It will change from compiler to compiler version and optimization level.
As others said you can read the assembler to know for a particular compilation if you are interested in micro-optimization, but in general it is nothing that you should even worry about.

You could take the adress of the variable and get a hint depending on the architecture. But this approach would probably force the compiler to allocate the variable in memory instead of a register.

Compile the C module to assembly and read that. Be aware that some compilers may perform whole-program optimization just before linking, so even the assembler output isn't 100% reliable.

Related

Reasons a C Compiler Ignores register Declaration

What are the reasons behind a C compiler ignoring register declarations? I understand that this declaration is essentially meaningless for modern compilers since they store values in registers when appropriate. I'm taking a Computer Architecture class so it's important that I understand why this is the case for older compilers.
"A register declaration advises the compiler that the variable in
question will be heavily used. The idea is that register variables
are to be placed in machine registers, which may result in smaller and
faster programs. But compilers are free to ignore the advice." ~ The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie
Thank you!
Historical C compilers might only be "smart" (complex) enough to look at one C statement at a time, like modern TinyCC. Or parse a whole function to find out how many variables there are, then come back and still only do code-gen one statement at a time. For examples of how simplistic and naive old compilers are, see Why do C to Z80 compilers produce poor code? - some of the examples shown could have been optimized for the special simple case, but weren't. (Despite Z80 and 6502 being quite poor C compiler targets because (unlike PDP-11) "a pointer" isn't something you can just keep in a register.)
With optimization enabled, modern compilers do have enough RAM (and compile-time) available to use more complex algorithms to map out register allocation for the whole function and make good decisions anyway, after inlining. (e.g. transform the program logic into an SSA form.) See also https://en.wikipedia.org/wiki/Register_allocation
The register keyword becomes pointless; the compiler can already notice when the address of a variable isn't taken (something the register keyword disallows). Or when it can optimize away the address-taking and keep a variable in a register anyway.
TL:DR: Modern compilers no longer need hand-holding to fully apply the as-if rule in the ways the register keyword hinted at.
They basically always keep everything in registers except when forced to spill it back to memory, unless you disable optimization for fully consistent debugging. (So you can change variables with a debugger when stopped at a breakpoint, or even jump between statements.)
Fun fact: Why does clang produce inefficient asm with -O0 (for this simple floating point sum)? shows an example where register float makes modern GCC and clang create more efficient asm with optimization disabled.

Shall I use register class variables in modern C programs?

In C++, the keyword register was removed in its latest standard ISO/IEC 14882:2017 (C++17).
But also in C, I see a lot, that more and more coders tend to not use or like to declare an object with the register class qualifier because its purposed benefit shall be almost useless, like in #user253751´s answer:
register does not cause the compiler to store a value in a register. register does absolutely nothing. Only extremely old compilers used register to know which variables to store in registers. New compilers do it automatically. Even 20-year-old compilers do it automatically.
Is the use of register class variables and with that the use of the keyword register deprecated?
Shall I use register class variables in my modern programs? Or is this behavior redundant and deprecated?
There is no benefit to using register. Modern compilers substantially ignore it — they can handle register allocation better than you can. The only thing it prevents is taking the address of the variable, which is not a significant benefit.
None of my own code uses register any more. The code I work on loses register when I get to work on a file — but it takes time to get through 17,000+ files (and I only change a file when I have an external reason to change it — but it can be a flimsy reason).
As #JonathanLeffler stated it is ignored in most cases.
Some compilers have a special extension syntax if you want to keep the variable in the particular register.
gcc Global or local variable can be placed in the particular register. This option is not available for all platforms. I know that AVR & ARM ports implement it.
example:
register int x asm ("10");
int foo(int y)
{
x = bar(x);
x = bar1(x);
return x*x;
}
https://godbolt.org/z/qwAZ8x
More information: https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/Explicit-Register-Variables.html#Explicit-Register-Variables
But to be honest I was never using it in my programming life (30y+)
It's effectively deprecated and offers no real benefit.
C is a product of the early 1970s, and the register keyword served as a hint to the compiler that a) this particular object was going to be used a lot, so b) you might want to store it somewhere other than main memory - IOW, a register or some other "fast" memory.
It may have made a difference then - now, it's pretty much ignored. The only measurable effect is that it prevents you from taking the address of that object.
First of all, this feature is NOT deprecated because: "register" in this context (global or local register variables) is a GNU extension which are not deprecated.
In your example, R10 (or the register that GCC internally assigns REGNO(reg) = 10), is a global register. "global" here means, that all code in your application must agree on that usage. This is usually not the case for code from libraries like libc, libm or libgcc because they are not compiled with -ffixed-10. Moreover, global registers might conflict with the ABI. avr-gcc for example might pass values in R10. In avr-gcc, R2...R9 are not used by the ABI and not by code from libgcc (except for 64-bit double).
In some hard real-time app with avr-gcc I used global regs in a (premature) optimization, just to notice that the performance gain was miniscule.
Local register variables, however, are very handy when it comes to integrating non-ABI functions for example assembly functions that don't comply to the GCC ABI, without the need for assembly wrappers.

How do I "tell" to C compiler that the code shouldn't be optimized out?

Sometimes I need some code to be executed by the CPU exactly as I put it in the source. But any C compiler has it's optimization algorithms so I can expect some tricks. For example:
unsigned char flag=0;
interrupt ADC_ISR(){
ADC_result = ADCH;
flag = 1;
}
void main(){
while(!flag);
echo ADC_result;
}
Some compilers will definitely make while(!flag); loop infinitive as it will suppose flag equals to false (!flag is therefore always true).
Sometimes I can use volatile keyword. And sometimes it can help. But actually in my case (AVR GCC) volatile keyword forces compiler to locate the variable into SRAM instead of registers (which is bad for some reasons). Moreover many articles in the Internet suggesting to use volatile keyword with a big care as the result can become unstable (depending on a compiler, its optimization settings, platform and so on).
So I would definitely prefer to somehow point out the source code instruction and tell to the compiler that this code should be compiled exactly as it is. Like this: volatile while(!flag);
Is there any standard C instruction to do this?
The only standard C way is volatile. If that doesn't happen to do exactly what you want, you'll need to use something specific for your platform.
You should indeed use volatile as answered by David Schwartz. See also this chapter of GCC documentation.
If you use a recent GCC compiler, you could disable optimizations in a single function by using appropriate function specific options pragmas (or some optimize function attribute), for instance
#pragma GCC optimize ("-O0");
before your main. I'm not sure it is a good idea.
Perhaps you want extended asm statements with the volatile keyword.
You have several options:
Compile without optimisations. Unlike some compilers, GCC doesn't optimise by default so unless you tell it to optimise, you should get generated code which looks very similar to your C source. Of course you can choose to optimise some C files and not others, using simple make rules.
Take the compiler out of the equation and write the relevant functions in assembly. Then you can get exactly the generated code you want.
Use volatile, which prevents the compiler from making any assumptions about a certain variable, so for any use of the variable in C the compiler is forced to generate a LOAD or a STORE even if ostensibly unnecessary.

is register data type variables are limited?

i totally stucked with this question, i had heard that there are 5 to 10 variables only can declare having datatype of register. i wish to know how many register datatype variables would be declare.it is pretty to seem. but this level of understanding we required while executing a programs.otherwise we mightstuck at runtime while execution thanks for your answers in advance
1).is registers(for datatypes) are vary to different types of compilers/machines??
2).how many register datatype variables could we pick ?
3).what are all these registers?(i mean cpu reg, memory reg, general purpose reg???)
register is no more a useful keyword in C programs compiled by a recent C optimizing compiler (e.g. recent versions of GCC or Clang/LLVM).
Today, it simply means that a variable qualified as register cannot be the operand of the & unary address-of operator (notice that register is a qualifier like const or volatile are, not a data type like int).
In the 1990s, register was then an important keyword for compilers.
The compiler (when optimizing) does a pretty good job about register allocation and spilling.
Try to compile your favorite C function with e.g. gcc -Wall -O2 -fverbose-asm -S; you'll get an assembly file suffixed .s and you could look inside it; the compiler is doing pretty well about register allocation.
Notice that GCC provides language extensions to put a few global (or local) variables in explicit registers. This is rarely useful, and it is target processor and ABI specific.
BTW, on desktop or laptop processors, the CPU cache matters a lot more than the registers (see references and hints in this answer to another question).
In C there is no way to explicitely define variable in CPU registers. You may barely hint a compiler with register specifier, but there is no point to do it nowadays, as compilers have sophisticated optimizer, which takes care of registers allocation.
do not use register. The optomizer will do a better job

Is it possible to instruct C to not zero-initialize global arrays?

I'm writing an embedded application and almost all of my RAM is used by global byte-arrays. When my firmware boots it starts by overwriting the whole BSS section in RAM with zeroes, which is completely unnecessary in my case.
Is there some way I can instruct the compiler that it doesn't need to zero-initialize certain arrays? I know this can also be solved by declaring them as pointers, and using malloc(), but there are several reasons I want to avoid that.
The problem is that standard C enforces zero initialization of static objects. If the compiler skips it, it wouldn't conform to the C standard.
On embedded systems compilers there is usually a non-standard option "compact startup" or similar. When enabled, no initialization of static/global objects will occur at all, anywhere in the program. How to do this depends on your compiler, or in this case, on your gcc port.
If you mention which system you are using, someone might be able to provide a solution for that particular compiler port.
This means that any static/global (static storage duration) variable that you initialize explicitly will no longer be initialized. You will have to initialize it in runtime, that is, instead of static int x=1; you will have to write static int x; x=1;. It is rather common to write embedded C programs in this manner, to make them compatible with compilers where the static initialization is disabled.
It turned out that the linker-script included in my toolchain has a special "noinit" section.
__attribute__ ((section (".noinit")))
/** Forces the compiler to not automatically zero the given global
variable on startup, so that the current RAM contents is retained.
Under most conditions this value will be random due to the
behaviour of volatile memory once power is removed, but may be used in some specific
circumstances, like the passing of values back after a system watchdog reset.
So all global variabeles marked with that attribute will not be zero-initialised during boot.
The C standard REQUIRES global data to be initialized to zero.
It is possible that SOME embedded system manufacturers provide a way to bypass this option, but there are certainly many typical applications that would simply fail if the "initialize to zero" wasn't done.
Some compilers also allow you to have further sections, which may have other characteristics than the 'bss' section.
The other alternative is of course to "make your own allocation". Since it's an embedded system, I suppose you have control over how the application and data is loaded into RAM, in particular, what addresses are used for that.
So, you could use a pointer, and simply use your own mechanism for assigning the pointer to a memory region that is reserved for whatever you need large arrays for. This avoids the rather complex usage of malloc - and it gives you a more or less permanent address, so you don't have to worry about trying to find where your data is later on. This will of course have a small effect on performance, since it adds another level of indirection, but in most cases, that disappears as soon as the array is used as an argument to a function, as it decays to a pointer at that point anyways.
There are a few workarounds like:
Deleting the BSS section from the binary or setting its size to 0 or 1. This will not work if the loader must explicitly allocate memory for all sections. This will work if the loader simply copies data to the RAM.
Declaring your arrays as extern in C code and defining the symbols (along with their addresses) either in assembly code in separate assembly files or in the linker script. Again, if memory must be explicitly allocated, this won't work.
Patching or removing the relevant BSS-zeroing code either in the loader or in the startup code that is executed in your program before main().
All embedded compilers should allow a noinit segment. With the IAR AVR compiler the variables you don't want to be initialised are simply declared as follows:
__no_init uint16_t foo;
The most useful reason for this is to allow variables to maintain their values over a watchdog or brown-out reset, which of course doesn't happen in computer-based C programs, hence its omission from standard C.
Just search you compiler manual for "noinit" or something similar.
Are you sure the binary format actually includes a BSS section in the binary? In the binary formats I've worked with BSS is simply a integer that tells the kernel/loader how much memory to allocate and zero out.
There definitely is no general way in C to get uninitialized global variables. This would be a function of your compiler/linker/runtime system and highly specific to that.
with gcc, -fno-zero-initialized-in-bss

Resources