Problem with Scope for constants

Hi, I am building an include file that will have basic constants and functions to be used in several sketches for this one project.

// common.h
//#define pos2   5            <-- tried this
//const int pos2 = 5;        <-- tried this  
static const int pos2 = 5;  <-- tried this  

int posStr(String aStr, int aPos); <-- just a function example
{ 
   stuff... return etc 
}
// END common.h
// main program aTest.ino
#include "common.h"
void setup()
{
}
void loop()
{ 
  String tStr = "1234567890";
  int tPos = posStr(tStr, pos2);
}

I get an error
aTest:32: error: 'pos2' was not declared in this scope

How do I declare pos2 and other consts in common.h so they can be used in the main sketches?

Thanks

A couple of things.

  1. In "common.h", you don't want to end this line with a semicolon:-
int posStr(String aStr, int aPos);
  1. You need to include "Arduino.h" in your "common.h" file.

Try these:-

// main program aTest.ino
#include "common.h"

void setup()
{
}
void loop()
{
    String tStr = "1234567890";
    int tPos = posStr(tStr, pos2);
}
// common.h
#ifndef _COMMON_H    
#define _COMMON_H    // Stops the header being included twice. (Standard practice)

#include <Arduino.h>

#define pos2   5
//const int pos2 = 5;  // This will work fine too.

int posStr(String aStr, int aPos) //<-- just a function example
{
    //stuff... return etc
    return 0;
}
// END common.h
#endif    // _COMMON_H

Occasionally you need to use the extern keyword to show to the compiler that you're using a variable or constant which is defined in an external file. Usually the system of .h header files means you don't need to do that.

MorganS:
Occasionally you need to use the extern keyword to show to the compiler that you're using a variable or constant which is defined in an external file. Usually the system of .h header files means you don't need to do that.

Yep. In this case, it compiles fine without 'extern'. (For me, at least.)

As a rule, I don't like to put executable code in a header file. Rather, I put it in another file with a *.cpp extension. I also dislike the String class because it bloats the code. So for your test program, you could try:

// main program aTest.ino
#include "common.h"

extern int pos2;        // Note the declaration here; not defintion

void setup()
{
  Serial.begin(9600);
}
void loop()
{ 
  char tStr[] = "1234567890";
  int tPos = posStr(tStr, pos2);
  Serial.print("Length is: ");
  Serial.println(tPos);
  Serial.println(tStr);
  
}

Many programmers are really sloppy about using the terms "define" and "declare". In this file, we declare pos2. The extern keyword says to the compiler: This variable is defined in some other file, but let me use it in this file as an int." Because pos2 is defined in the header file, think of the compiler typing in two question marks after pos2 in this file, which is a message to the linker to fill in the actual memory address of where pos2 really lives. (Yeah, I've taken a few liberties...)

In the header file, common.h we have:

int pos2 = 5;                                 // Definition of pos2
int posStr(char aStr[], int aPos);    // Declaration of posStr()

When the compiler sees the first line in the file, it allocates memory of pos2 which means it is a definition of pos2. The second line is a function prototype, which allows the compiler to perform type checking on the parameters and return type. Because there is no code for the function, it too is a declaration. All function prototypes are declarations, not definitions.

The third file is the *.cpp file, which I called posStr.cpp:

#include <string.h>

int posStr(char aStr[], int aPos)
{
  strcpy(aStr, "Hello");
  return strlen(aStr);
}

Because the code for the function is presented here, memory is allocated for the function, which makes this a function definition. The three files together form your program. In the IDE, you can use the little down arrow on the extreme right side of the IDE, below the "magnifying glass" to add and name file tabs in your program.

The distinction to remember is:

declaration: forms an attribute list (name, data type, scope, etc.) but does NOT allocate memory
definition: also forms an attribute list, but also allocates memory for the variable.

The extern keyword creates a data declaration for a variable (its attribute list) that is defined in some other file. This declaration allows you to use the variable in a file where it is not defined. Many programmers use declaration when they really mean definition.

Edit: Steve's way of preventing a "double include" using the #ifndef is a good practice to follow

Many thanks for the detailed responses. I will study them. I am on the steep learning C/C++ curve.

But in this case, it turned out to be a capitalization typo DUH! I am Dyslexic and sometimes it all looks good.

No guesses why I have been programming in Pascal for the past 35 years. :slight_smile:

WaitSome:
But in this case, it turned out to be a capitalization typo.....

No it wasn't.

What was the typo? I can't find it.

OldSteve:
#ifndef _COMMON_H
#define _COMMON_H // Stops the header being included twice. (Standard practice)

Thanks Steve,
I had wondered about seeing that in .h files, will do in future.

OldSteve:
No it wasn't.

Yup, it was.

I typed that stuff in from memory this morning instead of copy and pasting the actual code. I was on a tablet and not connected to the home network. Which also explains the ";" on the function. :slight_smile:

We can only go by what you posted, not what you meant to post.