I have a C codebase which uses unions for type punning. I am then unit testing this code in C++ with gmock.
I know union-based type punning is illegal in C++, so wanted to make sure my usage is safe:
// sum_halves.h
#include <stdint.h>
uint32_t sum_halves(unit64_t i);
// sum_halves.c
#include "sum_halves.h"
uint32_t sum_halves(unit64_t i) {
union {
uint64_t u64;
uint32_t u32[2];
} u;
u.u64 = i;
return u.u32[0] + u.u32[1];
}
// sum_halves_test.cpp
extern "C" {
#include "sum_halves.h"
}
#include <gtest/gtest.h>
TEST(sum_halves_test, two_plus_two_is_five) {
EXPECT_EQ(sum_halves(0x0000'0002'0000'0003), 5);
}
My understanding is that because sum_halves.c
is compiled as a C program, the union-based type punning is correct, even if I later call this function from C++ code. But if I made sum_halves
an inline function, then it would be compiled as a C++ code in *.cpp
files, resulting in Undefined Behavior. extern "C"
does not help as it only affects linkage, not compilation.
If I am correct, is there some workaround for the inline case? A GCC or Clang compiler flag or #pragma
to allow union-based type punning in a particular function?
Using C and C++ in the same program is undefined behavior for both the C standard and the C++ standard.
The behavior of sum_halves
by itself is defined by the C standard.
The behavior of sum_halves_test
by itself is defined by the C++ standard.
If the two routines are compiled separately in their respective languages, linked together with no intermodule interaction other than obeying the platform ABI (Application Binary Interface), then that linking plus the fact that each routine must conform to its language’s specifications means they will work together.