Global variable problems

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

Hi guys

 

Sorry if this is just a tad basic, but whilst debugging my keyboard interface project I located a problem:

I have very few global variables, but I noticed that when I try to update the value of one inside a function/main, it does not seem to update.

I did a little looking around and many C (non-AVR) projects seem to define their global vars the same as I have. Example:

 

int myvar;

int main (void)
{
    myvar = 1;
    if (myvar==1) do_stuff;
}

 

But if in my project I try something like the above the value of myvar never gets set to 1 and so do_stuff never happens.

 

I've tried defining myvar with volatile (and also with an initial value)  but this still hasn't helped:

volatile int myvar;

int main (void)
{
    myvar = 1;
    if (myvar==1) do_stuff;
}

 

I feel a bit daft asking about this and I'm sure that this worked prior to upgrading to AS7 from 6.2.

 

Any advice gratefully accepted. And please, be kind if I'm being stupid :D.

 

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

In C you can have different variables with the same name.

For example, in main() the local variable myvar is set to 1, and then do_stuff() is called.

In do_stuff() there is no local variable "myvar" and then when myvar is "printed" it will print: 34.

 

You probably have been moving the declaration of myvar around and have more than one copy with the same name.


int myvar = 34;

void do_stuff( voi) {
    
    print ( myvar);
}

int main (void)
{
    int myvar;
    
    myvar = 1;
    if (myvar==1) do_stuff();
    
    
}

 

For a more thourough explanation, look up a C tutorial and read up on the scope and duration of variables.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

banedon wrote:
But if in my project I try something like the above the value of myvar never gets set to 1 and so do_stuff never happens.

So post a full program with the "myvar" example.  Tell toolchain, version, build settings.  Tell AVR model.

 

Note that "do_stuff" must force an operation.  Otherwise it may well be discarded as a useless operation.

 

Similarly, there is no reason to make an assignment to [non]volatile] "myvar" unless there is a use later on.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Got it working, but I have no idea how.  I reloaded my design, removed 'volatile' from the global variable definitions, compiled, ran it in AVR, got same results. I then moved (cut/pasted) the global declarations from the very top of main.c to just above the function in question (still in main.c) and then it worked.

The only other thing I did was place a comment on the same line (to the right) of each global declaration in preparation to copy the source here.

I do have some declarations and consts which were between the function and the globals, but I can't see that this would make any difference.  Very odd!

Could me moving the globals cause the compiler to reassess the them and treat them correctly?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    myvar = 1;
    if (myvar==1) do_stuff();

My first be is that it would compile to :

    
    do_stuff();

Because the compiler know the value at compile time (and myvar isn't used anywhere else)

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

sparrow2 wrote:
My first be is that it would compile to :
Not if "myvar" is volatile it won't.

 

My best gues is that OP has posted a very simplified example of his code which is so much simplified that the error went away.

This is also confirmed by:

banedon wrote:
Got it working, but I have no idea how. I reloaded my design, removed 'volatile' from the global variable definitions, compiled, ran it in AVR, got same results. I then moved (cut/pasted) the global declarations from the very top of main.c to just above the function in question (still in main.c) and then it worked.
  "Randomly" changing code is not a good way to "fix" things, especially if:
banedon wrote:
but I have no idea how.
Re-read my post #2, and then check your source code for multiple declarations of the same variable. It is very likely that jou have not solved the problem, but only moved it to somewhere else and hidden it, and it will bite you later if you don't fix it now.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

I did check and there is only 1 declaration. I do understand that if you declare a variable globally and then locally, you will get two different variables and setting the value of one would not affect the other.

One thing to note is that I had line actually setting the variable just before an 'if' line testing that variable and it still didn't get set. Outputting the variable value to an LCD showed it to be 0 all the time.

I.e.

int testvar = 0;

int teststuff(void);
{
	testvar = 88;
	if (testvar == 88) LCD_sendtsr("88 (teststuff)");
	return(testvar);
}

int main (void)
{
	if (teststuff()==88) LCD_sendtsr("88 (main)");
}

 

Out of this scenario I got nothing printed to the LCD. If I then put another line in main under the if statement 'LCD_sendstr("finished")' then I'd get the 'finished' message.

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

Two things...
.
1) keep copy of both source and lss if you hit anything like this again
.
2) for that I'd highly recommend using a revision control system, commit at each significant incremental change, so you can wind back/forward to any step and you can compare any 2 versions to see the exact changes that made a difference
.
If the code really was as shown in #1 I'm totally with sparrow. Sure the compiler has to generate code to write the global (as it can't know if it might be accessed in another compilation unit) but there's no reason it would have generated code for the conditional as the outcome is known and fixed (true) at compile time.

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

Your program did not compile on the first try, I got:

paul@dualcore:~$ gcc asdf.c
asdf.c:12:1: error: expected identifier or ‘(’ before ‘{’ token
 {
 ^

After frowning for 2 seconds I saw an extra semicolon. My line nr 12 is your line nr 3.

The semi colon turns your function declaration into a function prototype and a loose piece of code.

It separates the function name from the body, and the function body is therefore never executed.

 

After fixing that and adding an LCD_sendtsr() substitute:

#include <stdio.h>

int testvar = 0;

void LCD_sendtsr( char *String) {
	printf( "%s", String);
}

int teststuff(void)
{
	testvar = 88;
	if (testvar == 88) {
		LCD_sendtsr("88 (teststuff)");
	}
	return testvar;
}

int main (void)
{
	if (teststuff()==88) {
		LCD_sendtsr("88 (main)");
	}
}

and then compiling it on my pc, and executing the program, I get the expected output:

paul@dualcore:~$ gcc asdf.c
paul@dualcore:~$ ./a.out
88 (teststuff)88 (main)

Doing little experiments like this is much easier on a PC.

On a PC you also have access to better tools such as a debugger.

I do want to recommend to add curly braces to all if statements. It makes the code easier to read if there is never more than one statement on a line.

 

It is also often considered wrong to let an embedded program (such as AVR) reach the end of main().

 

Note:

"a.out" is the default name of the compiler output if no name is given for the executable.

sendtsr() not sendstr() ?

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

Last Edited: Sun. Apr 22, 2018 - 05:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

banedon wrote:
I did check and there is only 1 declaration.

Will you PLEASE post a complete small test program, so that we may all play along on the home game?  As it is, we have no idea what is in the source file other than your narration.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Paulvdh wrote:
On a PC you also have access to better tools such as a debugger.

Although PC-native stuff certainly is a load more convenient, note that Debuggers are also available for AVRs!

 

And, in fact, most microcontrollers today.

 

Atmel Studio includes a debugger.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can one be warned that global variables have the same name as local variables (and other name collisions : often, it does not matter -ex : indexes are usually called i, j, -k fro 3 D arrays-, but it seems useful).

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

I'm pretty sure the higher level warnings may do this - but failing that you can use a proper static code analyser (lint, splint, Klockwork, QAC, etc) all of which will almost certainly catch this kind of thing.

 

EDIT: tried to prompt it to give a warning with:

#include <avr/io.h>

int main(void) {
    int foo;
    {
        int foo;
        
        foo = 37;
    }
    foo = 59;
}

then:

C:\SysGCC\avr\bin>avr-gcc -mmcu=atmega16 avr.c -Wall -Wextra
avr.c: In function 'main':
avr.c:6:13: warning: variable 'foo' set but not used [-Wunused-but-set-variable]
         int foo;
             ^
avr.c:4:9: warning: variable 'foo' set but not used [-Wunused-but-set-variable]
     int foo;
         ^

But that's not really the warning I was looking for. I suppose it is a perfectly valid thing to do so the compiler probably thinks "why would I bother warning about that?"

 

Need to try a static analyser.

Last Edited: Tue. Apr 24, 2018 - 12:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope, tried cppcheck which you can "play" with online at:

 

http://cppcheck.sourceforge.net/...

 

but it just says:

Cppcheck 1.83

[test.cpp:8]: (style) Variable 'foo' is assigned a value that is never used.
[test.cpp:6]: (style) Variable 'foo' is assigned a value that is never used.

Done!

which is no better than the C compiler itself.

 

I know a powerful tool like QAC or Klockwork would probably have more to say (I've spent days clearing other people's Klockwork warnings!) but the problem is that it's not easy to try those in isolation without a lot of "infrastructure" around them.

Last Edited: Tue. Apr 24, 2018 - 12:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

splint worked

$ cat pasbo.c

int main(void) {
    int foo;
    {
        int foo;

        foo = 37;
    }
    foo = 59;
    return foo;
}

spplint protested once

splint pasbo.c
Splint 3.1.2 --- 05 May 2014

pasbo.c: (in function main)
pasbo.c:5:13: Variable foo shadows outer declaration
  An outer declaration is shadowed by the local declaration. (Use -shadow to
  inhibit warning)
   pasbo.c:3:9: Previous definition of foo: int

Finished checking --- 1 code warning

-> splint seems interesting and easy to install (installed from source on cygwin, is a debian package for any architecture)

 

Last Edited: Tue. Apr 24, 2018 - 01:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice find - yup, splint always impressed me more than cppcheck among the "free" ones. The problem for avr-gcc is that it can be quite tricky to persuade it to ignore a lot of the "complex stuff" in the headers derived below io.h

 

Right at the end of WinAVR I think Eric added it to the distribution but I remember not having a lot of success configuring it to scan "real" AVR code at the time. It's fine for the kind of "generic C" example shown in that "foo" test though.