2

I have a strange error concerning the inline keyword, this is just a sample code I wrote:

#include <stdio.h>
#include <stdint.h>

uint8_t inline LIB_MATH_BTT_u8GetMSBSetBitPos(uint32_t args_u32Variable)
{
    uint8_t local_u8MSBSetBitPos = 0;
    args_u32Variable = args_u32Variable >> 1;
    while (args_u32Variable != 0)
    {
        args_u32Variable = args_u32Variable >> 1;
        local_u8MSBSetBitPos++;
    }
    return local_u8MSBSetBitPos;
}

int main() {
    int x  = LIB_MATH_BTT_u8GetMSBSetBitPos(17);
    printf("%d", x);
    return 0;
}

I ran this code on Visual studio 2022 and this was the result:

4

and the same code was run on Clion with toolchain from MinGW and this was the result:

====================[ Build | untitled | Debug ]================================
"C:\Program Files\JetBrains\CLion 2022.3.2\bin\cmake\win\x64\bin\cmake.exe" --build C:\Users\User\CLionProjects\untitled\cmake-build-debug --target untitled -j 12
[1/2] Building C object CMakeFiles/untitled.dir/main.c.obj
[2/2] Linking C executable untitled.exe
FAILED: untitled.exe 
cmd.exe /C "cd . && C:\PROGRA~1\JETBRA~1\CLION2~1.2\bin\mingw\bin\gcc.exe -g  CMakeFiles/untitled.dir/main.c.obj -o untitled.exe -Wl,--out-implib,libuntitled.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Program Files\JetBrains\CLion 2022.3.2\bin\mingw\bin/ld.exe: CMakeFiles/untitled.dir/main.c.obj: in function `main':
C:/Users/User/CLionProjects/untitled/main.c:6: undefined reference to `LIB_MATH_BTT_u8GetMSBSetBitPos'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

so I am so confused why the same code was run successfully on Visual Studio 2022 but failed on Clion.

PS. the code worked successfully on Clion if I removed the inline keyword.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
abdo Salm
  • 1,678
  • 4
  • 12
  • 22

2 Answers2

3

From the C Standard (6.7.4 Function specifiers)

7 Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

So as this function

uint8_t inline LIB_MATH_BTT_u8GetMSBSetBitPos(uint32_t args_u32Variable)

has external linkage then the linker searches its external definition and does not find it.

Either you need to provide an external definition of the function (defining it with storage class specifier extern) or you could declare the function with internal linkage as for example

static uint8_t inline LIB_MATH_BTT_u8GetMSBSetBitPos(uint32_t args_u32Variable)

and in this case it will be enough to use the inline definition of the function with internal linkage.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • I also found a note (6.7.4.11) under the example in 6.7.4 that also makes that clear: _"Because `cels` has external linkage and is referenced, an external definition has to appear in another translation unit"_ – Ted Lyngmo Aug 06 '23 at 11:48
1

why the same code

Because that different compiler makes different decisions. Having an inline function with external linkage allows the compiler to choose from the inline version or an external non-inline non-static version of the function. Clion compiler chooses to use the external version, because you did not provide one, it fails to compile.

Consider not using inline. If you want to use inline, consider researching why would you want to use it and what does it exactly mean. Nowadays, compilers are smart and fast enough so we can just have static functions if we want them inlined.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111