Hi, I'm about to pull my hair out.
I have a enumerated type in a file called iap_tools.h that looks like this:
enum ChipType { master_chip, slave_chip, comm_chip };
I have a function declared in master.c that looks like this:
void start_firmware_copy( enum ChipType chip_type ){}
I have its prototype in a file called master.h, and it looks like this:
void start_firmware_copy( enum ChipType chip_type );
In master.h and master.c, I've #include "iap_tools.h", so everyone should know about the enumerated ChipType. But when I compile, I get this error:
*** ERROR C230 IN LINE 173 OF MASTER.H: 'ChipType': unknown struct/union/enum tag
So just for fun, I copy the ChipType definition into master.h, but it complains that master_chip (etc) was redefined and that ChipType was a duplicate struct/union/enum tag! It knows darn well what ChipType is! Why is it giving me an error? I use other enumerated types exactly (as far as I can tell) the way I've used ChipType, and they work just fine.
If I change the enumerated type to an unsigned char, everything compiles fine.
So does anyone have a clue what's going on here?
Thanks, -JB
In master.h and master.c, I've #include "iap_tools.h", so everyone should know about the enumerated ChipType.
And you're absolutely sure you have that #include before the line that uses the enum?
Yes. Exceedingly sure. And anyway, the fact that I redefined it above where I use it, and it complains, should be enough to know it has the definition. All the errors I've gotten are compiler errors, not linker errors.
should be enough to know it has the definition
"Should be" doesn't cut it. We have to make sure.
Compose a strictly minimal example source (without any preprocessor commands in it) that still show the problem. Show that here, along with the exact compiler invocation and output, and people can actually try to find out what's going on here.
All the errors I've gotten are compiler errors, not linker errors.
The fact you found it necessary to point that out hints at an underlying misunderstanding about how the compiler and preprocessor work. Of course the linker has nothing to do with it!
I can't remember why I brought up the linker. My apologizes.
I tried to break all the relevant code into it's own project, but it compiled just fine.
I #include "iap_tools.h" at the top of master.h, where the use of ChipType is located. And iap_tools.h has the definition of ChipType. But when I copy/paste the definition of enum ChipType into master.h (right below the #include "iap_tools.h"), master.h doesn't have an error anymore. But iap_tools.h has a "duplicate struct/union/enum tag". Which implies that iap_tools.h isn't being #included as I ask it to in master.h.
I have iap_tools.h wrapped in:
#ifndef _IAP_TOOLS_H_ #define _IAP_TOOLS_H_ #endif /* _IAP_TOOLS_H_ */
Is it possible that this causes the compiler to skip over iap_tools.h after it sees it the first time, even when it needs it in a second file? Would it keep _IAP_TOOLS_H_ but not the definition of ChipType?
I #include "iap_tools.h" at the top of master.h, where the use of ChipType is located.
Given the importance of exact sequence you should know of by know, that's at least dangerously fuzzy wording. "At the top ... where" is not enough. It has to be above the usage.
But when I copy/paste the definition of enum ChipType into master.h (right below the #include "iap_tools.h"), master.h doesn't have an error anymore. But iap_tools.h has a "duplicate struct/union/enum tag". [emphasis mine]
That makes no sense. If you add your copy of the definition below the #include, then it must be your copy, not iap_tools.h, that "has" the errors.
But all this suggests a possible cause for this problem --- mutual inclusion. If each of "master.h" and "iap_tools.h" include each other, it won't have seen all of one when it includes the other. To see if that is your problem, you have to exctract preprocessor output and check the sequence and nesting of #include files.
Oh and this:
#define _IAP_TOOLS_H_
is a bad idea. You're intruding on implementor namespace. As tempting as it may be: do not use leading underscores in your own source unless you're implementing your own C compiler or its runtime library.
BAM! As soon as I read "mutual inclusion" I was certain that was the problem. I moved some things around in my header files and it compiled cleanly. Thanks for your help!
(And come on; does anyone really need to be told that you have to #include the definitions above their use?)
Have you ever heard of someone overwriting compiler namespace when using the _H_ notation? This seems to be a super-common practice.
"And come on; does anyone really need to be told that you have to #include the definitions above their use?"
Unfortunately, there are plenty of examples of posters here who really do need to be told such basic things as that...
:-(
"Have you ever heard of someone overwriting compiler namespace when using the _H_ notation? This seems to be a super-common practice."
The fact that it's common doesn't make it right; The fact that a lot of people get away with it doesn't make it right.
"Have you ever heard of someone overwriting compiler namespace when using the _H_ notation?
It is not the "_H_" suffix part that's the problem. The problem is the leading underscore.
Sadly enough: yes.
Have you ever heard of someone overwriting compiler namespace when using the _H_ notation?
It's not the H_ notation, it's the leading '_' part only. For extra protection from silly surprises, you may even want to make that macro name something like COMPANY_PRODUCT_COMPONENT_FILE_H
But anyway the above is the wrong question. The correct question is: do ever you want to end up being that someone, instead of just hearing about them? As you've just experienced first hand, trouble-shooting pre-processor issues is quite tricky enough without the code kicking the tools' feet out from under them.
Violating the naming rules is a silly risk not worth taking, especially since it's so trivially easy to just get it right.
This seems to be a super-common practice.
The relevant counter-argument involves the super-common practice of what billions of flies eat. I'll spare us all the full text.
I realize the leading underscore is the problem, but I've seen _FILENAME_H_ used in so many places, it seems highly unlikely that the compiler would create it's own tags with "_H_" in the name. But I get your point.
When I feel tired of working, I'll go through and add COMPANY_NAME to those headers. And in the meantime, if fly-dinner hits the fan, I won't say you didn't tell me so. :)
I normally use C++ with namespaces containing company name for compiler symbols, and #include guards with company name.
I wonder how many files "list.h" there are in this world that are protected by #ifdef _LIST_H.