So, I have a file structure like this:
- FileA
- FileB
- FileC
FileA includes FileB and FileC
FileB has:
#define image(i, j, w) (image[ ((i)*(w)) (j) ])
and FileC has:
#define image(i, j, h) (image[ ((j)*(h)) (i) ])
on compilation i get:
warning: "image" redefined
note: this is the location of the previous definition ...
Does this warning mean it changes the definition of the other file where it found it initially when compiling ?
Is there any way to avoid this warning while maintaining these two defines, and them applying their different definitions on their respective files?
Thankyou in advance :)
CodePudding user response:
Does this warning mean it changes the definition of the other file where it found it initially when compiling ?
The program is ill-formed. The language doesn't specify what happens in this case. If the compiler accepts an ill-formed program, then you must read the documentation of the compiler to find out what they do in such case.
Note that the program might not even compile with other compilers.
Is there any way to avoid this warning while maintaining these two defines, and them applying their different definitions on their respective files?
Technically, you could use hack like this without touching either header:
#include "FileB"
#undef image
#include "FileC"
But a good solution - if you can modify the headers - is to not use macros. Edit the headers to get rid of them. Use functions instead, and declare them in distinct namespaces so that their names don't conflict.
Some rules of thumb:
- Don't use unnecessary macros. Functions and variables are superior to macros.
- Follow the common convention of using only upper case for macro names, if you absolutely need to use macros. It is important to make sure that macro names don't mix with non-macros because macros don't respect namespaces nor scopes.
- If you need a macro within a single header, then undefine it immediately when it's no longer needed instead of leaking it into other headers.
- Don't use names without namespaces. That will lead to name conflicts. Macros don't respect C namespaces, but you can instead prefix their names. For example, you could have
FILE_B_IMAGE
andFILE_C_IMAGE
(or something more descriptive based on the concrete context).
They are not functionally equivalent, one can be seen as a row-wise iteration and the other a column-wise
This seems like a good argument for renaming the functions (or the macros, if you for some reason cannot replace them). Call one row_wise
and the other column_wise
or something along those lines. Use descriptive names!
CodePudding user response:
Does this warning mean it changes the definition of the other file where it found it initially when compiling ?
For GCC (tagged) it means that the definition processed second is used from the point of the redefinition onward, including not only in the same file but at any places later in the translation unit where the macro identifier appears followed by a (
. Previous appearances will have used the previous definition.
Neither the C language specification nor the C language specification provides a more general answer: the redefinition other than with an identical token sequence violates language constraints, therefore both the translation behavior and the execution behavior of a program containing such a non-matching redefinition are undefined.
Is there any way to avoid this warning while maintaining these two defines, and them applying their different definitions on their respective files?
If these definitions are meant to be used only within their respective files, then the easiest solution would be for each file to #undef image
at the end. This would work in both C and C .
If both are intended to be exposed for use by other files then you have a name collision that you will have to resolve one way or another. You might, for instance, add a distinguishing prefix to the definition and all uses of each one. In C only, you also have the option of resolving the name collision by changing the macros to [inline] functions and putting them in different namespaces. That would probably make it easier to adapt each one's users to the new names than prefixing the names would do.
CodePudding user response:
As @Jarod42 said, an inline function will solve the problem.