1

I'm doing some (maybe exotic) experiments about C++ inline functions in VS2019:

source1:

#include "pch.h"

inline int inline_func(int i) {
    return  i;
}

void testinline1()
{
    inline_func(0);
}

source2:

#include "pch.h"

inline int inline_func(int i) {
    return  i*i ;
}

void testinline2()
{
    inline_func(0);
}

main source:

#include "pch.h"

inline int inline_func(int i);
int main(int argc,char* argv[])
{   
    int i = inline_func(2);
}

According to "Storage classes of inline functions" section of http://en.wikipedia.org/wiki/Inline_function,

In C++, a function defined inline will, if required, emit a function shared among translation units, typically by putting it into the common section of the object file for which it is needed. The function must have the same definition everywhere, always with the inline qualifier.

The definitions of inline_func in source1 and source2 is different so there should be errors, but there is no such error in VS2019.

The result of i in main() is 2 which is from the inline_func in source1, this seems to be a random choice by the building process since if I comment testinline1 in source1, then i will become 4 since the inline_func in source1 won't show up in the object file without being used in the same source. When I comment testinline2 in source2 too there will be undefined symbol error for inline_func as expected.

Why does these happen? Is this where C++ doesn't cover or only MSVC doesn't cover?

Updated after answered:

Here is a better example:

source1:

#include "pch.h"

int non_inline_func();
inline int inline_func2() {
    return  non_inline_func();
}

static int non_inline_func()
{
    return 1;
}

int public_func1() 
{
    return inline_func2();
}

source2:

#include "pch.h"

int non_inline_func();
inline int inline_func2() {
    return  non_inline_func();
}

static int non_inline_func()
{
    return 2;
}

int public_func2()
{
    return inline_func2();
}

main source:

#include "pch.h"

int public_func1();
int public_func2();

void TestInline()
{
    int i =public_func1();
    int j= public_func2();
}

The result is i=j=1. The definition of the inline functions are the same here. This should violate this: https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule

name lookup from within each definition finds the same entities (after overload-resolution)

jw_
  • 1,663
  • 18
  • 32
  • 3
    _The definitions of inline_func in source1 and source2 is different so there should be errors_ This will cause Undefined Behavior. It's a violation of ODR if I'm right. Another question is whether diagnostic is required by the standard... – Scheff's Cat Dec 09 '19 at 08:34
  • 1
    Found on [cppreference.com](https://en.cppreference.com/w/cpp/language/inline): _There may be more than one definition of an inline function or variable (since C++17) in the program as long as each definition appears in a different translation unit and (for non-static inline functions and variables (since C++17)) all definitions are identical._ and _If an inline function or variable (since C++17) with external linkage is defined differently in different translation units, the behavior is undefined._ Diagnostics not mentioned (or I overlooked it). – Scheff's Cat Dec 09 '19 at 08:37
  • The end of the first sentence, "typically [...]", is a figment of the author's imagination. – molbdnilo Dec 09 '19 at 08:40
  • "there should be errors" Sure, you've made one. – n. m. could be an AI Dec 09 '19 at 14:47
  • @molbdnilo I have not seen counterexamples so far, have you? – n. m. could be an AI Dec 09 '19 at 15:02
  • similar question: https://stackoverflow.com/questions/10671956/same-class-name-in-different-c-files – jw_ Dec 20 '19 at 01:20

2 Answers2

4

From this One Definition Rule (ODR) reference:

If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the program is ill-formed, no diagnostic required.

[Emphasis mine]

If you have an ODR-violation (which you have since the two definitions are not identical) the compiler doesn't have to emit a warning or error message.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

Interestingly, in MSVS2019 ISO C++ 14...

The inline function :

inline uint32_t hanoi(int a) { __asm  bsf eax, a } // Solve arbitrary 'Tower of Hanoi' round

Called with either :

int numMoves = (1<<numDisks)-1; /* Calculate number of moves needed to solve */

// Print full Tower Of Hanoi solution
for (int i = 1;i < numMoves;i++) {
    printf("move disk %u %s\n", hanoi(i), hanoi(i) & 1 ? "left" : "right");
}

or, just :

hanoi(1);

Doesn't inline. It always results in a "Call" being emitted by the compiler : /

Same when I :

  • use std::cout ... like a good boy ; )
  • call the function directly (discarding) or;
  • call the function directly (utilizing return value)

and irrespective of whether :

  • Passed parameter is immediate/literal
  • Passed parameter is stack local variable
  • Passed parameter is heap allocated static global
  • Function is changed to be uint32_t f(void) { return 1; } <-- surprised me!

I notice that folks far cleverer than I have complained about similar in-lining issues in VS2015 and VS2017 - each comparing it to identical code in CLANG and GCC, whos compilers don't seem to have any issue : / Each time MS appear to have identified it as a compiler issue.

TBH, it looks like VS may just be a little 'fragile' when it comes to in-lining functions :(

Just my 2c

\o/ - "don't shoot!"

Gary C
  • 321
  • 2
  • 4