Cannot define function in #define /#else sequence

Why can’t I define a function in this snippet?

[code]
#ifdef __FLASH
  const __flash int var = 1;
  int read_var (void)          
  {
    return var;
  }
#else
#include <avr/pgmspace.h> /* From AVR-LibC */  commenting this and following line - same result 
 const int var PROGMEM = 1;
 int read_var (void)
here is the source of error message 
Audio_Loopback_26.ino: In function 'void setup()':
Audio_Loopback_26:205: error: a function-definition is not allowed here before '{' token
 {
    return (int) pgm_read_word (&var);
 }
#endif /* __FLASH */

The only error message

Audio_Loopback_26.ino: In function ‘void setup()’:
Audio_Loopback_26:205: error: a function-definition is not allowed here before ‘{’ token

[/code]

Sort the tags out. Post code, not snippets. You should know this by now.

Your code fragment makes no sense to me. The statement:

  const __flash int var = 1;

is supposed to do what?

Also, in:

#include <avr/pgmspace.h> /* From AVR-LibC */  commenting this and following line - same result 
 const int var PROGMEM = 1;                                    // <--- What does this line mean?
 int read_var (void)
here is the source of error message                            // <--- Why is this line here?
Audio_Loopback_26.ino: In function 'void setup()':e            // <--- Why is this line here?
Audio_Loopback_26:205: error: a function-definition is not allowed here before '{' tokene            // ????
 {
    return (int) pgm_read_word (&var);
 }

Further, even if your code compiled, you define var as a const yet you have a function to read it. Why? True you can change a const definition through a pointer, but why would you do that? Perhaps posting all of your code would help us understand what you are trying to do.

Vaclav:
Why can’t I define a function in this snippet?

Why do you even post snippets?

http://snippets-r-us.com/

const __flash int var = 1;

__flash is the new avr-gcc feature for dealing with variables in flash memory. It happens at the compiler level, so you no longer need avr-libc functions like pgm_read_word(). See https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html

I can't figure out the error based on the snippet, either.

Probably because the IDE mangles INO files, so what is compiled is not what you see. Look at Audio_Loopback_26.cpp in the temp build folder to see what is actually compiled.

As I thought you already knew, since you started a thread about it, the IDE gets confused by #ifdefs in INO files. It is better to put such stuff into a cpp file and the main INO file as simple as possible.

The following complete example compiles ok on 1.5.7 :

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

//#undef __FLASH
#ifdef __FLASH
  const __flash int var = 1;
  int read_var (void)          
  {
    return var;
  }
#else
#include <avr/pgmspace.h> /* From AVR-LibC */
 const int var PROGMEM = 1;
 int read_var (void)
 {
    return (int) pgm_read_word (&var);
 }
#endif /* __FLASH */

Where did you guys get a version of avr-gcc that supports __flash?

The following complete example compiles ok on 1.5.7 :

Yes, but it doesn't use __flash. Try this:

#ifdef __FLASH
#error foo
#endif

void setup() { }
void loop() { }

No error message, therefore this feature is not available. That's on IDE 1.5.8.

It’s been in gcc 4.7.x for some time, 1.5.7 uses gcc 4.8.1

The following complete example compiles ok on 1.5.7 :

Yes, but it doesn’t use __flash. Try this:

Duh… you need to remove the comment on the #define ! For obvious reasons, a single example can’t exercise both branches of the #if.

I guess __FLASH is user defined, but the OP is not very forthcoming.

The example I posted works in 1.5.7, 1.5.8 with or without __FLASH defined…

No error message, therefore this feature is not available. That’s on IDE 1.5.8.

That just means you haven’t defined __FLASH, but __flash IS implemented.

bobcousins:
Duh… you need to remove the comment on the #define ! For obvious reasons, a single example can’t exercise both branches of the #if.

What comment?

#ifdef __FLASH
#error foo
#endif

void setup() { }
void loop() { }

That just means you haven’t defined __FLASH, but __flash IS implemented.

No, it isn’t:

const __flash int var = 1;

int read_var (void)          
{
  return var;
}

void setup() { }
void loop() { }

Error on IDE 1.5.8:

sketch_oct06a.ino:1:7: error: '__flash' does not name a type
sketch_oct06a.ino: In function 'int read_var()':
sketch_oct06a.ino:5:10: error: 'var' was not declared in this scope
Error compiling.

Compiler:

$ /home/nick/Development/arduino-1.5.8/hardware/tools/avr/bin/avr-g++ --version

avr-g++ (GCC) 4.8.1

Your exact example, with __FLASH defined:

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

#define __FLASH
#ifdef __FLASH
  const __flash int var = 1;
  int read_var (void)          
  {
    return var;
  }
#else
#include <avr/pgmspace.h> /* From AVR-LibC */
 const int var PROGMEM = 1;
 int read_var (void)
 {
    return (int) pgm_read_word (&var);
 }
#endif /* __FLASH */
sketch_oct06a.ino:14:9: error: '__flash' does not name a type
sketch_oct06a.ino: In function 'int read_var()':
sketch_oct06a.ino:17:12: error: 'var' was not declared in this scope
Error compiling.

Huh. Seems to work in avr-gcc 4.8.1, but not in avr-g++:

BillW-MacOSX-2<10166> /usr/local/CrossPack-AVR-48/bin/avr-g++ -mmcu=atmega328p flash.c
flash.c:3:7: error: '__flash' does not name a type
 const __flash int x = 12;
       ^
flash.c: In function 'int main()':
flash.c:6:13: error: 'x' was not declared in this scope
     PORTB = x;
             ^

 
BillW-MacOSX-2<10167> /usr/local/CrossPack-AVR-48/bin/avr-gcc -mmcu=atmega328p flash.c

Interesting. However I can't see any easy way (or any way at all) of using that usefully.

Huh? It lets you put things in flash and access them without remembering that you need pgm_read_xxx() function calls. Basically, the compiler knows that things that are in "named address spaces" need a more complex access function than a simple load/store, and has a set of them that it can apply... It'll solve all manner of beginner pgmspace issues. Maybe.

not in avr-g++

The compiler gurus at avr-freaks points out that this is an implementation of a C language extension (NOT something avr-gcc-specific) that isn't even present in C++ (and might not be compatible with C++.)

westfw: Huh? It lets you put things in flash and access them without remembering that you need pgm_read_xxx() function calls.

OK, post an example that prints from PROGMEM (using Serial.print) using the __flash concept.

I don’t know whether the memory space counts as a type distinguisher. Without that, it could presumably be used exactly the way the current “help” type is used. Except that it seems academic - I got this further reply on AVRFreaks:

(Georg-Johan Lay) who implemented __flash in avr-gcc for us has said that the ruling committee for C++ have their head too far up their arse (my words not his!) to ever consider adding anything to the core language that might support Harvard address spaces. So it’s a pretty fair bet avr-g++ is NEVER going to get _flash and will always have to use the pgm_read*() kludge from AVR-LibC.

I don't see how having it in C (but not C++) will be particularly useful. Since the type isn't known to C++ you could never have it in (say) a .h file, and thus can never get at the PROGMEM data in any useful way (eg. for use in a class, or to send to Serial print).

I don't think the current situation is particularly bad. For one thing, the F() macro is reasonably easy to use. For another, if you make a template class like I did here:

http://www.gammon.com.au/forum/?id=12615&reply=3#reply3

... then you can easily access PROGMEM. It's just that you have to remember to do it, but then you have to remember lots of things when programming.

In another thread I showed how you can put a font table into PROGMEM with only a couple of changed lines. And big things like font tables are the very things you probably want to convert.

Well how useful this is I don’t know. But you can get the ifdef example to work.

The ino file

extern "C"
{
  int read_var();
}

int flashVar;

void setup()
{
  
  Serial.begin(9600);
  
  flashVar = read_var();
  
  Serial.print("Variable from flash = ");
  
  Serial.println(flashVar);
    
}

void loop() 
{

}

The c file

#ifdef __FLASH
const __flash int var = 111;
 
int read_var (void)
{
  return var;
}
#else
#include <avr/pgmspace.h> 
 
const int var PROGMEM = 222;
 
int read_var (void)
{
  return (int) pgm_read_word (&var);
}
#endif

Compile with 1.5.8 and you get 111, compile with 1.0.6 and you get 222. Delete the build folder when changing IDE’s – at least I was getting goofy results without doing this.

Confirmed, but I don't know how useful this is. After all, the variables in question have to go into a .c file, you have to write "accessor" functions, so you can get at them from C++, and at present anyway you still have the pgm_read_word stuff anyway, so this has just increased the complexity. At the end of the day, the variables end up in flash. You don't actually save any program space (compared to doing it with PROGMEM), it just looks neater. Or, it would if you didn't have to do all that mucking around.