Preprocessor Issue

Okay, so I’m a bit baffled with what the preprocessor is trying to do.

I have the following

#if 0
null
#endif

#include "WProgram.h"
#include <Ethernet.h>

#define MAX_PARAMS 8
#define MAX_PARAM_LENGTH 64

class Query
{
...

And it compiles fine. But if I remove line 2, or the first three lines, I get:

Test:0: error: 'EHTTPCode' has not been declared
Test:1: error: 'CGIMethod' does not name a type

Those two types are defined further down in my code. As long as I keep those three lines in, and as long as they are in the file before any non-preprocessor code (it works up until the first class is defined), then the file compiles okay.

I’m just going to keep the lines there, as they aren’t hurting anything; but I would like to know what could be causing this issue.

I’ll attach the file if someone wants to see if it’s just my installation that is not working right.

Test.pde (6.47 KB)

Okay, I’ve narrowed it down to all the relevant bits. Still no idea why it works when I leave the first three lines up.

#if 0
null
#endif

#include "WProgram.h"

typedef enum
{
	HTTP_CODE_200,
	HTTP_CODE_404
} EHTTPCode;

void SendHTTPCode(EHTTPCode err)
{
	switch (err)
	{
		case HTTP_CODE_200:
			// send a standard http response header
			Serial.println("HTTP/1.1 200 OK");
			Serial.println("Content-Type: text/html");
			Serial.println();
			break;
		case HTTP_CODE_404:
			Serial.println("HTTP/1.1 404 NOT FOUND");
			Serial.println("Content-Type: text/html");
			Serial.println();
			break;
		default:
			Serial.println("HTTP/1.1 500 Internal Server Error");
			Serial.println("Content-Type: text/html");
			Serial.println();
	}
}

typedef char *(*CGIMethod)(char *);

namespace Command
{
	char *GetRecipe(char *)
	{
		return "";
	}
}

CGIMethod GetCGIMethod(char *path)
{
	struct { char *name; CGIMethod func; } commands[] = {
		{ "GET_RECIPE", Command::GetRecipe }
	};
	
	for (int i = 0; i < sizeof(commands) / sizeof(*commands); i++)
	{
		if (1)
			return commands[i].func;
	}
	
	return 0;
}

void setup()
{
	Serial.begin(9600);
}

void loop()
{
	SendHTTPCode(HTTP_CODE_404);
	GetCGIMethod("GET_RECIPE");
}

Okay, I think it has something to do with how .pde files are preprocessed. I exported everything to a cpp file and it works as expected. The only problem with that is I don't know how to access libraries from cpp files; it can't find the headers.

So I'm either stuck with a monolithic file with three useless lines at the top, or logical bits torn apart and divided into various source files and headers. Guess I'll stick with the former, unless someone has a better solution.

The GetCGIMethod function needs explaining. You have a for loop that contains an interesting if statement. The if statement will always evaluate to true or false (I know which; do you?). If true, the method returns commands[0].func, making the loop useless.

If false, the loop accomplishes nothing, and the function returns 0.

In either case, what is the purpose of defining an array of functions when only the first will ever be returned? What is the purpose of the for loop?

kidmosey: Okay, I think it has something to do with how .pde files are preprocessed.

It does. I've solved a similar problem by putting the typedef in it's own tiny library and #including it.

PaulS: The GetCGIMethod function needs explaining. You have a for loop that contains an interesting if statement. The if statement will always evaluate to true or false (I know which; do you?). If true, the method returns commands[0].func, making the loop useless.

That was my cut down version of the function. I removed everything that wasn't necessary to reproduce the results; in this case it was a stricmp() call and the other function definitions.

I also removed the client definition, as that was dependent on an external library. Interesting that you didn't think printing http headers to serial was strange :D

wildbill: It does. I've solved a similar problem by putting the typedef in it's own tiny library and #including it.

Well, I guess now you know an easier way around it. Does this make me an accidental genius?