Static Guide

Go To Last Post
33 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have learnt C++ before at school, then C. Haven't got a formal training in C like C++, mostly self taught. The idea of using static variables and static functions are not yet clear for me. As much as i know that if a static variable is declared in a class,it is shared by all the objects of the class, and a static functions is used to work with the static variables.

But here in Joey's code i see -

/* Serial calibration program. Untested. */

#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>

static int usart_put(char c, __attribute__ ((__unused__)) FILE *stream) {
  while (!(UCSRA & (1<<UDRE)));
  UDR = c;
  return 0;
}

int main(void) {

    static FILE usart = FDEV_SETUP_STREAM(&usart_put, NULL, _FDEV_SETUP_WRITE);

    stdout = &usart;
    UBRRL = 51;
    UCSRB = (1<<TXEN);
    OSCCAL = 0;

    do {
        _delay_ms(50);
        printf("OSCCAL=%u\r\n", OSCCAL);
        _delay_ms(50);
    } while (++OSCCAL);

    while (1);

}

/* 9600 baud @ 8 MHz */
/* 1200 baud @ 1 MHz */

Why did he use static in the function, usart_put ( ). What are the general guidelines for a function to be static in gcc ?

 

Can i / should I use static in simple adc read functions like this -

int adc_read()	// adc read function
{
	ADCSRA|=(1<<ADSC);
	
	while(bit_is_set(ADCSRA,ADSC));

	return ADC;
}

Also, why don't we see static before functions like this - 

void adc_setup()	// adc setup function for ATtiny 13A
{
	ADMUX|=(1<<MUX0);  //Adc at pin 7
	ADMUX=(1<<REFS0);
	
	ADCSRA|=(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
}

 

This topic has a solution.
Last Edited: Sun. Feb 14, 2016 - 04:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's static and there's static. static applied to a function declaration limits the visibility to that file. Static applied to a variable means the variable will be retained even if the function is exited - like a global but with limited visibility. It means the compiler allocated memory for it rather than creating it at run time on the stack.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It means the compiler allocated memory for it rather than creating it at run time on the stack.

Is this the reason why there should not be many static functions or variables in the program ? Because it will hold memory permanently ?
Does it also answer that why we usually don't put static over functions like adc init and usart_init ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In microcontrollers, memory limited so you want to use it wisely. You probably wouldn't declare a variable static unless you needed to. You still need to have enough ram to hold your globals,statics,locals and stack.

Say we write a group of functions for the adc. We'd most likely put them in one file. If we declared adc_init static, then it wouldn't be visible outside that file - how could we call it from main? Static on a function can give the compiler some hints to optimise the code. It also tells you that it is local to that file.

Basically, use when needed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Static on a function can give the compiler some hints to optimise the code. It also tells you that it is local to that file.

Basically, use when needed.

Is it the reason why usart_put function in Joey's code decalared as static ? As Because it will be called everytime anything is send through usart, so there wont be any problem if memory is allocated for it permanently. Have i reasoned it right ?
Would that mean that i should declare functions like adc_read etc. static ? Though people dont do it usually.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I remember C, declaring a variable outside of a function as static is the same as declaring a function static.  This makes it have file scope.  It's a C programmer's pathetic attempt to do what classes do in C++.  smiley

 

Declaring a variable that is inside a function as static makes it not be an automatic but I don't know what it would be called.  It also restricts the scope to the function.  This is the same in C++.  I rarely find a use for this.

 

You can program AVRs with C++.  I've been doing it for 10 years.  I think it often makes the code less efficient but I'm more concerned with the damaged brain cells I would get by using C.  smiley  Besides, I blame Atmel for this, not C++.  smiley 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In C++ I rarely have functions called usart_init() etc..  We call them constructors.

Last Edited: Sat. Feb 13, 2016 - 01:41 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "static" on Joey's function above means "this function is only used within this one file so should not be visible to any other .c files that are built as part of this project". If usart_put() were not static then a callable copy would be created and its name would appear as a global symbol in the linker map.

 

"static" in C is very confusing as the same thing can have at least three (that I can instantly think of) implications depending on where it is used.

 

1) on a global variable it just means - this is limited to this file alone and cannot be seen elsewhere

 

2) on a function I suppose it's the same thing in that it's also saying "name limited to visibility only within this one file"

 

3) on a variable inside a function - the name of that is already of limited scope (cannot be seen/accessed outside the function) but now it effectively means "the value in this remains for the next time the function is called". Any initial value given is just applied the first time the function is called (actually it really happens before that as it's part of _do_copy_data()/_do_clear_bss() in the CRT before main() is entered).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
You can program AVRs with C++. I've been doing it for 10 years. I think it often makes the code less efficient

C++ does not, in general, make code less efficient. It's all down to how you use the language. There is no inherent property of C++ making an implementation of a specific algorithn less efficient than the corresponding implementation in C.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Sat. Feb 13, 2016 - 01:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote

In C++ I rarely have functions called usart_init() etc..  We call them constructors.

True. They initialise objects for you and also does the job of destroying them (destructors) whenever the objects become out of scope without you getting a headache for it.
But i am liking the C style more for programming avrs'. Maybe because of its simplicity yet powerfulness.
P.S: Maybe powerfulness is grammatically wrong but i was not getting any other word for it at that time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff you thoroughly mentioned the uses of declaring variables and functions static. Are there any benefits of doing this ?
I mean if i write a .c file which i know i wont be using anywhere else in any way, then should i declare all functions as static ? To optimise in a way by avoiding the "callable copy" made by the linker.
For example if i have a program for adc and pwm which i wont use anywhere else, should i declare all the functions as static for optimisation and some other benefits ?
Another question, which isn't related to this, im just confused by its name, does linker in gcc mean compiler ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

steve17 wrote:You can program AVRs with C++. I've been doing it for 10 years. I think it often makes the code less efficient

C++ does not, in general, make code less efficient. It's all down to how you use the language. There is no inherent property in C making an implementation of a specific algorithn less efficient than the corresponding implementation in C.

I was thinking of the AVR.  I assume class data is referenced through address registers.  I don't think AVRs have many of those.  I have the feeling that accessing I/O registers are less efficient.  Especially those at low memory where C code would use the special I/O instructions.

 

It's never been a problem for me though, and it makes for code that is easier to write and read, in my opinion.

 

Last Edited: Sat. Feb 13, 2016 - 02:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One of the main benefits is avoiding "name pollution". It could well be that you have modules for all of timer, UART and ADC and they all have a variable called "counter". It's all an aid to modularisation. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Steve, if you don't know then don't spread unfounded rumours about the efficiency of C++ on AVR. I've actually been amazed by the efficiency of some of the code it generates at the assembler level. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
I was thinking of the AVR. I assume class data is referenced through address registers. I don't think AVRs have many of those. I have the feeling that accessing I/O registers are less efficient.

My emphases in the quote above says it all, but who am I to resist a good rant.. ;-)

 

Class data is accessed the same way in C++ as struct data is accessed in C.

If I/O registers are accessed in a less efficient way in your C++ compiler than e.g. in the avr-gcc C compiler then you should i) blame the compiler maker, not the C++ language, and ii) consider changing compiler.

 

Instead of assuming, have you thought of actually looking at the generated code before FUDding on this scale? You must have been here long enough to be aware that whenever these unfounded claims (OK, assunptions, guesses...) are made  I will react and argue. Put the actual facts on the table. Else refrain.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So any function can be declared static which isn't shared by files. What i get is, there is no harm in making some functions static which are called more than once like usart_put and usart_get and adc_read etc.
Except not sharing the variables/functions between files are there some more incidences where you all declare functions as static ? I mean is it a good practice to declare functions as static in a .c file which is not to be shared with others ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

static applied to a variable or function at file scope makes it "local" to that file.

If the compiler can see all uses of a variable or function,

optimization might cause it to disappear.

 

Also, there is the name pollution issue.

If I cannot think of a good name for a variable or function,

I have a habit of calling it fred.

Better a meaningless name than a misleading one.

fred should not be global.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To be honest, if you want a good description of the uses of "static" and why you would be best off getting a good book about C programming where the author has spent time formulating a good description and making it complete. 

 

On the whole the computer scientists will tell you that isolating and localising data is better the more you can do it. "static" is one of the routes to that goal. C++ takes all this to a new level if you are interested in such concepts - things there can be kept very "private:" ;-) 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

One of the main benefits is avoiding "name pollution". It could well be that you have modules for all of timer, UART and ADC and they all have a variable called "counter". It's all an aid to modularisation. 

I not only avoid name pollution, I avoid code pollution.  I only have one class for timers, UARTs, etc., because they all work the same.  The only difference is the address of their I/O registers.

 

All UARTs work the same so I only write the code once.  All timer/counters work the same too,  so I only have one copy of this code.

 

All the timer/counter work is done in the Counter_regs class.  I do have a small class for each timer/counter but all they do are inherit Counter_regs, and set the address.

Similarly all the UART work is done in 2 classes, Usart and Usart_regs.  Again there is a small class for each UART but all they do are inherit Usart_regs and set the address and "bit shift" to 0 or 4.  The bit shift is necessary because there are 2 UARTs per I/O register.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

steve17 wrote:I was thinking of the AVR. I assume class data is referenced through address registers. I don't think AVRs have many of those. I have the feeling that accessing I/O registers are less efficient.

My emphases in the quote above says it all, but who am I to resist a good rant.. ;-)

 

Class data is accessed the same way in C++ as struct data is accessed in C.

If I/O registers are accessed in a less efficient way in your C++ compiler than e.g. in the avr-gcc C compiler then you should i) blame the compiler maker, not the C++ language, and ii) consider changing compiler.

 

Instead of assuming, have you thought of actually looking at the generated code before FUDding on this scale? You must have been here long enough to be aware that whenever these unfounded claims (OK, assunptions, guesses...) are made  I will react and argue. Put the actual facts on the table. Else refrain.

I have looked at it.  In my C++, everything is a class.  In C code that isn't the case.  One easy example is accessing I/O registers in low memory where faster instructions can be used.  In C, these addresses are absolute so the compiler can tell if the fast instructions can be used.  In my C++, these addresses are address register indirect, if that is the proper name.  The compiler can't tell what the this pointer will be so it can't use the faster instructions.

 

This is why I say, jokingly, that the problem is Atmel's, not C++.

Last Edited: Sat. Feb 13, 2016 - 05:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One reason I use C++ is so I can run my AVR code on the PC.  I don't know how to handle the absolute addresses on the PC.  By using new to get the I/O register addresses, and by using #ifdef _WIN32, I can put the I/O registers on the heap on the PC.

 

This ability to run the code on the PC was more important in the old days when Atmel Studio's debugging of the C++ code was very poor.  It's still handy though.  It saves wear and tear on the flash and I think the Microsoft debugger is still a bit handier for debugging.  Sometimes testing on the PC where I can simulate the peripherals can be easier and quicker than testing on the real hardware.

Last Edited: Sat. Feb 13, 2016 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
In my C++, these addresses are address register indirect, if that is the proper name.

I can't decipher that. Can you show an example?

 

Let's do another quote:

steve17 wrote:
One easy example is accessing I/O registers in low memory where faster instructions can be used. In C, these addresses are absolute so the compiler can tell if the fast instructions can be used. In my C++, these addresses are

I can't read that "In my C++" in any any other way than as "in how I have coded my classes in C++". It seems to me you are arguing that the C++ compiler creates inefficient code, while it is actually your usage of C++ that makes the code inefficient.

 

I'm challenging you on the pure basics here:

 

if you code

PORTB = 1;

will your C++ compiler not generate a single sbi instruction for this? (Not all compilers do. The avr-gcc C compiler didn't in the past.)

 

steve17 wrote:
In my C++, everything is a class. In C code that isn't the case.

If you want to claim that C++ comes out unfavorably in a comparison for code effectiveness you must compare on equal terms. Right now you're just saying "the way I implemented it in C++ the code comes out less efficient than if I implement it in C.

 

Assuming the case in C++ is that "everything is a class" (a nice approach, but I'd formulate it "everything is an object") then what you need to compare with in C is functions working on data passed to them in structs (and of those structs are to be mutable (i.e. changes made by a function to the data in the struct are to persist after the function exits) then you need to pass a pointer to the struct to the function. (Just passing the struct will of-course pass a copy so changes will not be persistent). Do you recognise the this-pointer in slight disguise here. Yes, this is exactly how all C++ compilers I have see implements it. I'd be surprised if a C++ compiler would generate less efficient code for this than the corresponding C case.

 

Bottom line is that you have made claims above regarding the effectiveness of the language itself. You base those claims on your usage of the language and/or an unfair comparison case in C.

 

Innocent readers might read your posts as that there is some inherent stuff in C++ making it less efficient than C. There isn't so don't claim that.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

steve17 wrote:In my C++, these addresses are address register indirect, if that is the proper name.

I can't decipher that. Can you show an example?

Let's say we want to perform a software reset.  I like to use the reset registers because they are simple. 

 

Here's the way I do it.   Note: I can't make the "Add code" thing work.

 

#include "reset_regs.h"

(new Reset_regs)->Do_software_reset();

 

How would you do it?   No, I don't want to know.smiley   My way takes a few more microseconds.  No problem, I can wait.

 

Of course I need the Reset_regs class.  Note: The register class knows it's address.  I could fetch the address a couple of ways.  I do it by overloading the new operator.  The problem with operator overloading is, it confuses readers who don't know it's been done.  I guess I chose this method because of my devious character.smiley

 

Lets try this without the malfunctioning "Add code" button.  Note, the only thing I use out of the io......h file is the address.

 

#ifndef RESET_REGS_H
#define RESET_REGS_H

 

#include <stdlib.h>     // for size_t in new and delete operators
#include <avr/io.h>
#include "myTypes.h"
#include "cpu_regs.h"

 

class Reset_regs   {

private:
   union Status   {
      struct  {
         Register power_on                    : 1;  // PORF
         Register external                    : 1;  // EXTRF
         Register brownout                    : 1;  // BORF
         Register watchdog                    : 1;  // WDRF
         Register PDI                         : 1;  // PDIRF
         Register software                    : 1;  // SRF
         Register reserved                    : 2;  // Reserved
         } bits;
      u_int8 byte;
   };

   volatile Status status;                             // STATUS  0x00

 

   struct Control   {
      Register software                    : 1;  // SWRST
      Register reserved                    : 7;  // Reserved
      };

   volatile Control control;                           // CTRL    0x01

 

public:

   void Do_software_reset()   {
      Cpu_regs* cpu_regs_p = new Cpu_regs;
      cpu_regs_p->Disable_configuration_change_protection();
      control.software = true;
      }

 

   bool Is_software_reset()   {
      return status.bits.software;
      }

 

   void Clear_software_reset()   {
      Status my_status;
      my_status.byte = 0;
      my_status.bits.software = true;
      status.byte = my_status.byte;
      }

 

   void Clear_resets(u_int8 which)   {
      which ^= status.byte;
      status.byte = which;
      }

 

   void* operator new(size_t objsize)   {
      return (void*)_SFR_ADDR(RST);        // assign actual memory location of the registers
      }

   };
#endif

 

 

 

 

Last Edited: Sat. Feb 13, 2016 - 07:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just gleeming over the source.

 

I see the inefficiency of the indirection you need to make

 

(new Reset_regs)->Do_software_reset();

but that is only due to the object being allocated dynamically. There would be no difference in indirection inefficiency if you would allocate a C struct dynamically. Same cost.

 

If the C programmer argues that he can do it without dynamic allocation, then your answer would be "so can I":

 

Reset_regs reset_regs;

.
.
.

reset_regs.Do_software_reset();

I do understand that in this specific case it does not matter that this takes a little extra time. I also LOL'ed at your humorous remark about it. :-)

 

But the bottom line is that the example you've shown just shows how the code becomes a bit inefficient because of the way you've chosen to use C++.

 

Also, since this now is touching on how to encapsulate hardware registers at specific addresses, I'll tip you off to go check if your C++ compiler supports "placement new". It's introduced in C++-11 IIRC, so you might be out of luck. If it's there, it will save you some coding and possibly bugs.

 

I'll stop now. We've derailed this thread enough already.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

 I'll tip you off to go check if your C++ compiler supports "placement new".

I've been using placement new for several years.  I don't see why it would be useful here.   The class should know what its address is, not the caller.

 

Well, maybe I get your point.  I could have the class have the address as a constant.  Then I could fetch it and use it in a placement new.  That would be a nice way to eliminate the overloading. 

Last Edited: Sat. Feb 13, 2016 - 07:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

getting a good book about C programming

Any recommendations. I mean not online stuff, any book that i can buy and read. I have no idea about good C books.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well everyone writing C should have Kerninghan and Ritchie so I'd start there. (2nd edition -  the ANSI one). 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Kerninghan

Cliff, if you call it K&R, you won't run the risk of misspelling Kernighan.smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just took the spelling that SwiftKey on my tablet offered ;-) 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestions and clearing my static doubt about static :-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
if you code

PORTB = 1;

will your C++ compiler not generate a single sbi instruction for this? (Not all compilers do. The avr-gcc C compiler didn't in the past.)

Shouldn't do it now either.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:

JohanEkdahl wrote:
if you code

PORTB = 1;

will your C++ compiler not generate a single sbi instruction for this? (Not all compilers do. The avr-gcc C compiler didn't in the past.)

Shouldn't do it now either.

 

Bad typo there.. Sorry. Let's do better:

PORTB |= 1;

 

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]