Help understanding additional tabs in IDE

I'm confused how adding a tab affects my sketch. The following sketch compiles just fine:

byte somesmallnumber;
void setup()
{
}
void loop()
{ 
}

But if I add a tab called newtab.h and move "byte somesmallnumber" into it. I get the error "byte does not name a type"

Here's the main sketch

#include "newtab.h"
void setup()
{  
}
void loop()
{ 
}

Here's newtab.h

byte somesmallnumber;

Can someone explain what's happening?

You need to include either Arduino.h or WProgram.h/WConstants.h (depending on whether you are using at least IDE 1.0 or an older IDE).

I have this in my internal button library:

#ifndef Newtab_h
#define Newtab_h

#include <stddef.h>
#include <stdlib.h>
#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"

#else
#include "WProgram.h"
#include "WConstants.h"
#endif

and then at the end:

#endif // Newtab_h

In the newtab.h file you want to put a reference to the variable:

extern byte somesmallnumber;

And in the newtab.cpp file you want the definition:

#include "newtab.h"

byte somesmallnumber;

And then in your code you need to include the newtab.h file:

#include "newtab.h"

You need to create both newtab.h and newtab.cpp. Note, things in your sketch will only know about things in the .h file if you include it, and similarly in newtab.cpp…

ScottG:
I just tried that and I still get the same error.

I only use the IDE to compile and upload to the board, but I had to put the .h and .cpp files in the include directory in my sketchpad directory on my Linux system. You may have to put the files in the correct directory on Windows to get them read in, or get answers from somebody who actually uses the IDE to create new tabs.

MichaelMeissner:

ScottG:
I just tried that and I still get the same error.

I only use the IDE to compile and upload to the board, but I had to put the .h and .cpp files in the include directory in my sketchpad directory on my Linux system. You may have to put the files in the correct directory on Windows to get them read in, or get answers from somebody who actually uses the IDE to create new tabs.

I was replying to a different post, I should have quoted it. I tried adding "extern" before "byte" but that didn't work.

ScottG:
I was replying to a different post, I should have quoted it. I tried adding "extern" before "byte" but that didn't work.

Yes, that post seems to have disappeared. It was there when I was editing my original reply, and then gone.

MichaelMeissner:
You need to create both newtab.h and newtab.cpp. Note, things in your sketch will only know about things in the .h file if you include it, and similarly in newtab.cpp…

Okay, that’s a bit familiar from looking at library files. What if my 2nd tab is not a .h, but just a plain simple name with no extension? Does the IDE behave differently?

The reason I’m asking is I want to modify my w5100.h file and use a “#if defined” statement to initialize a different Slave Select pin for my Ethernet shield. But w5100.h doesn’t see my defined name because of the order things are compiled. Someone told me I need to move my #define and the #include <ethernet.h> into a separate tab. This would force things to compile in such a way so my #define is compiled before w5100.h. When I started moving things to the new tab I was getting errors I didn’t understand. So now I’m trying to figure this multiple tab thing out.

Wanting to break my lengthy sketch to more manageable chunks I discovered the tabs feature. If there is no extension on the tab it compiles as if it were just one tab. For example, if you make a tab named loop and put the loop function in there it will compile fine.

If the tab has an extension it has to be included, ie: #include "foo.h"

I created a sketch with the main tab, and a newtab.h and newtab.cpp tabs. When I compile I get this error:
…newtab.cpp:5: undefined reference to `somesmallnumber’

Here’s the main tab:

#include "newtab.h"
extern byte tabtest();
void setup()
{  
 byte h =  tabtest();
}
void loop()
{ 
}

Here’s newtab.h

#include <arduino.h>
extern byte somesmallnumber;

Here’s newtab.cpp

#include "newtab.h"
extern byte tabtest()
{
  somesmallnumber  = 5;
  return somesmallnumber;
}

somesmallnumber is not defined anywhere. The extern reference to it in newtab.h tells the compiler that some other file has the definition for it, but in your case none do. You need to define it somewhere, presumably in the main tab.

wildbill:
somesmallnumber is not defined anywhere. The extern reference to it in newtab.h tells the compiler that some other file has the definition for it, but in your case none do. You need to define it somewhere, presumably in the main tab.

Oh, I thought extern byte somesmallnumber; was defining it.

So if in my main tab if I add this:
byte somesmallnumber; Then I could use it in my main tab and also in newtab.cpp

ScottG:
Oh, I thought extern byte somesmallnumber; was defining it.

So if in my main tab if I add this:
byte somesmallnumber; Then I could use it in my main tab and also in newtab.cpp

In C++, you must have only one definition, and everywhere else is just a reference. Extern just creates a reference, and the definition must be elsewhere.

As a side note, in C according to the standard, you too must only have one definition, and all other places must be a reference. However, a common extension is that if you have

unsigned char somesmallnumber;

in multiple files, that the compiler would create a common definition for the variable. However, it is invalid from a strict standards point of view. Given Arduino is C++ and not C, this is more just of a footnote, in case you notice multiple definitions in other code.

In general, if you define

extern byte somesmallnumber;

in newpat.h, you should have the definition of it in newpat.cpp. You could have the definition in some other file, like the main sketch, but it is generally a cleaner style to have the newpat.cpp provide the definitions. The idea is the the .h file provides the public definitions used, while the .cpp file provides the default implementation.