Say I have a macro UNIQUE_NAME(PREFIX)
that concatenates __LINE__
to PREFIX
:
#define CONCAT2_EXPAND(a, b) a ## b
#define CONCAT2(a, b) CONCAT2_EXPAND(a, b)
#define UNIQUE_NAME(prefix) CONCAT2(CONCAT2(prefix, _), __LINE__)
Now if this macro was to be used in an inline
function, included in two different translation units, then the expanded code of the inline
function would differ between the two translation units (unless they have the same includes).
Is this behavior defined, unspecified, implementation-defined, or undefined?
This is what I got during a code review:
You're caught between a rock and a hard place here. Using
__LINE__
is a bad idea, because there's nothing preventing me from callingUNIQUE_NAME
twice on the same line, and then it's not really unique any longer, is it?__COUNTER__
would give a unique name, but it'd be too unique: ifUNIQUE_NAME
was used in aninline
function, included in two different translation units, then the expanded code of theinline
function would differ between the two TUs (unless they have the same includes), which is Undefined Behavior. – @Matthieu M.
If it helps, I am confused about having a static inline
function and an inline
function (if it matters which one) in a header file and including it in different .c
files.
Say:
[[gnu::always_inline]] static inline void foo(void)
{
bool UNIQUE_NAME(bar);
// ...
}
and
inline void foo(void)
{
bool UNIQUE_NAME(bar);
// ...
}
I believe the reviewer meant the second one, and not the first one.
static inline
is different frominline
in the sense, that you can't have two TUs including the header with justinline
, as it will constitute duplicate definition.static
will make it "visible" only in the including TUs, so each can have it's own copy.inline
withoutstatic
leads to confusion — I don't do it in my own code. Usingstatic inline …
avoids most (if not all) of the problems with definitions vs uses. The residual issue is "if the function is not inlined, then each object file that calls the function has a copy of the function". For me, that's an acceptable risk. If the function might not be inlined, it probably shouldn't be declared inline. GCC seems to inline functions extensively — creating a static (not inline) function that's called from one line of code in the file often leads to that function being inlined.inline void foo(void) { ... }
, you have created an inline definition of a function with external linkage, which is not an external definition. But there still needs to be an external definition, and the compiler is allowed to use it instead of the inline definition (it is unspecified which is used). So in your example, the compiler probably declined to inline the function for whatever reason, emittedcall foo
instead, and then failed to link because there is no out-of-line definition offoo
.