14

I was checking out some code written for STM32F microcontroller and I found these keywords used before initializing a variable. I would like to know what is the significance of using this "__IO" & "static" keywords?

The line of code was given like that:

static   __IO   uint32_t   sysTickCounter; 
Naasif
  • 495
  • 2
  • 6
  • 13
  • 1
    `__IO` is probably a macro that can be either `volatile` or nothing – Jean-François Fabre Jul 14 '18 at 09:20
  • 1
    `static`, well, it means that it's restricted to this scope (file or function) but global (not automatic variable) – Jean-François Fabre Jul 14 '18 at 09:20
  • @Jean-FrançoisFabre Thank you. But in the case of "static", once I used a static varible in another C file by including it. Then how can it became restricted when I was able to use it on another file? would you mind to explain that? – Naasif Jul 14 '18 at 09:39
  • 1
    of course if you _include_ the C file (not recommended) then the variable is visible in the file you're including from – Jean-François Fabre Jul 14 '18 at 09:39
  • So, if I don't include it in another file, is there any chance of getting used by another c program? I mean why should I need that "static" keyword then? Would you mind to explain please? – Naasif Jul 14 '18 at 09:45
  • 2
    you don't need `static` unless the variable is defined with the same name in some other file. – Jean-François Fabre Jul 14 '18 at 09:46
  • @Jean-FrançoisFabre Thank you. I have understood. But I found another problem. Listen, I have two c file one is containing main method and another one is containing only an int variable a=10; I had included the other one into the main function. When I was trying to call printf("value: %d",a); from main function, it showed an error. Thant means I can't use non-static variable from another file(main) even if I include it in main. So, What would you say? Can you please explain that? – Naasif Jul 14 '18 at 10:31
  • 1
    We are not a personal tutoring service. Comments are not for extended discussion or asking/answering further questions. All your questions will be answered by a textbook. Please get one; don't try learning C from obscure online tutorials or youtube videos. – too honest for this site Jul 14 '18 at 12:01
  • 1
    https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files – JimmyB Jul 17 '18 at 15:13

1 Answers1

24

__IO / volatile

__IO is not a C keyword. __IO is a macro for volatile - defined in STM32 standard peripheral library header files. E.g., in core_cm4.h (might be in a CMSIS sub-folder), you will find

#define     __IO    volatile

(If you use gcc's -E option to use only the pre-processor stage, you can see the macro's expansion.)

The volatile keyword, in turn, is often applied to a variable to prevent the compiler from 'optimizing it out'. This is useful in embedded systems - where a variable might be used within an interrupt - and compiler optimizations could cause problems.

Short example ...

int main(void) {
    int ms = 0;

    ms++;
    while (1);

    return 0;
}

Here is the generated assembly (using sdcc compiler for PIC12f629 target). As you can see, the ms variable has been 'optimized out'.

_main:
; 2 exit points
_00113_DS_:
;   .line   18; "main.c"    while (1)
    GOTO    _00113_DS_
    RETURN
; exit point of _main

If, on the other hand, we declare the variable as volatile ...

volatile int ms = 0;
ms++;
// etc.

the relevant instructions are preserved:

_main:
; 2 exit points
;   .line   16; "main.c"    volatile int ms = 0;
    CLRF    _main_ms_1_5
    CLRF    (_main_ms_1_5 + 1)
;   .line   19; "main.c"    ms++;
    INCF    _main_ms_1_5,F
    BTFSC   STATUS,2
    INCF    (_main_ms_1_5 + 1),F
_00113_DS_:
;   .line   21; "main.c"    while (1)
    GOTO    _00113_DS_
    RETURN
; exit point of _main

static

The effect of the static keyword depends on the scope in which the variable is declared.

  • file scope - the variable's scope is limited to the current compilation unit (usually a file plus its #included header files).
  • block scope (e.g. within a function) - The variable is preserved in memory for the duration of the program. (For a function, this means that the value of the variable is preserved between subsequent calls to the function.)

Notes

  • As vlk pointed out in a comment, another important use of volatile is for accessing peripheral registers (although you would use a pointer in that case).
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
David Collins
  • 2,852
  • 9
  • 13
  • Thank you so much. I have got it completely. So whenever we define something like #define something 1234, the something becomes a macro. Am I right? I had a confusion with it. Anyway, I have another request for you. Would you mind to explain bit more about this line, "This is useful in embedded systems - where a variable might be used within an interrupt - and compiler optimizations could cause problems" ? – Naasif Jul 14 '18 at 10:41
  • 4
    good answer, but this is not only for interrupts, but main purpose is to define variables mapped at addresses where MCU has peripheral and system registers, such as GPIO, SYSTICK, RCC, ..... because access to these registers can not be optimized. – vlk Jul 14 '18 at 11:19
  • @Olaf Would you please explain that? – Naasif Jul 14 '18 at 12:25
  • 1
    @naasif How checking the standard or at least a good C textbook? – too honest for this site Jul 14 '18 at 12:31
  • @Olaf Yeah. I have understood. Look I have no books at this time. So If you explain me a little bit that would help me a lot.That's it. Thank you. – Naasif Jul 14 '18 at 12:42
  • 1
    Fine, @naasif , I'll bite: http://port70.net/~nsz/c/c11/n1570.html And "I have no books at this time" - That's the problem. Get one. – too honest for this site Jul 14 '18 at 12:44
  • 1
    @Olaf you do not know if it is wrong as you do not know the scope of the variable. If it was declared in automatic variables scope it is wrong, but if in the global one it is right, as the variable will be in the static storage. So at most : it might be wrong depending on the variable scope – 0___________ Jul 14 '18 at 13:12
  • 2
    David. It does not prevent any optimizations. The `volatile` only guarantees that the variable will read from its storage location every time it is used, and stored after every change.https://godbolt.org/g/hgv4hD – 0___________ Jul 14 '18 at 13:19
  • 1
    @PeterJ_01: … which makes the original statement wrong - as I wrote. (FTR there is no "automatic variable scope" (this would exclude `static` storage class variables as these are explicitly not automatic). You mean block/function scope.) – too honest for this site Jul 14 '18 at 13:22
  • 1
    @Olaf: I have updated my answer. Nonetheless, I am curious if you can outline a plausible scenario where a `volatile` `sysTickCounter` variable - whose name clearly indicates it is be updated inside a SysTick IRQ handler - would _not_ be declared at file scope. – David Collins Jul 15 '18 at 10:51
  • 1
    If it's only used in a function, why would one define it at file-scope? Re making it `volatile (although not using the macro, it's to accomodate non-standard legacy compilers which used their own keywords for peripheral hardware registers, i.e. `__IO` does not necessarily mapo to `volatile`): It is commonly used to keep the compiler from optimising out memory accesses during debugging, e.g. for a watchpoint. – too honest for this site Jul 15 '18 at 10:59
  • 1
    First rule on SO: don't make assumptions about how code not shown looks like. Even for code shown it's way too often not the code OP aks about. – too honest for this site Jul 15 '18 at 11:05
  • 1
    @vlk: Thanks for your input. I have updated my answer with notes. – David Collins Jul 15 '18 at 21:58
  • 3
    `volatile` is *essential* for anything that's not under full control of the compiler. The compiler does not know if/when/that an ISR using a variable is ever executed and hence might not see the relevance of accessing its current value. Memory-mapped IO is outside of compiler's control too: Writing to an IO location will have an effect on the hardware even though the compiler thinks it doesn't matter because the value is never read back. Reading an IO location may yield different results each time although the software did not write to the location. That's why `volatile` is needed. – JimmyB Jul 17 '18 at 15:07