User Tools

Site Tools



  • Need to fix C headers to not have C++ keywords.
  • Need to add code to verify/enforce bool compatibility between C and C++.
  • Otherwise, the general mechanics for C/C++ interop apply (need to use extern “C” on C++ side).

Notes and details below.

Trying to just compile existing C code as C++ will likely cause many errors and may have potential functional differences (not likely, but possible).

C/C++ interop is well supported. We can compile C files as C into object files and C++ as C++ into object files and link them without issue.

To access C functions from C++, C++ code will need to include the C headers (wrapping in extern “C” { }).

To access C++ functions from C, C++ needs to declare the function inside extern “C” { }.

The extern “C” { } forces C++ to use C naming convention in object file (instead of doing C++ name mangling), which allows the C++ and C objects to link properly.

So we have to make sure that any header file used by both C and C++ is compatible with both. For existing C files the big sticking points will be use of C++ keywords. Renaming can clear most of this up, but bool typedefs is another story.

In C++ bool is a keyword and built in type. In C we just typedef it. Can we somehow make C bool and C++ bool 100% compatible, such that we can guarantee the size is the same and we can pass bool values between C and C++ code without worrying about strange or undefined behavior? Answer: I think so…

#ifndef BOOLTYPE_H
#define BOOLTYPE_H
/* */
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
/* These can't be used after statements in c89. */
#ifdef __COUNTER__
  #define STATIC_ASSERT(e,m) \
    enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/static_cast<int>(!!(e)) }
  /* This can't be used twice on the same line so ensure if using in headers
   * that the headers are not included twice (by wrapping in #ifndef...#endif)
   * Note it doesn't cause an issue when used on same line of separate modules
   * compiled with gcc -combine -fwhole-program.  */
  #define STATIC_ASSERT(e,m) \
    ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(int)(!!(e)) }
typedef unsigned char C_bool_t;
#define C_TRUE 1
#define C_FALSE 0
#if !defined(__cplusplus)
  typedef C_bool_t bool;
  #define true C_TRUE
  #define false C_FALSE
  /* verify compatibility between C and C++ booleans */
  STATIC_ASSERT(sizeof(C_bool_t) == sizeof(bool), C_CPP_bool_size_mismatch);
  STATIC_ASSERT(C_TRUE == true, C_CPP_true_equiv);
  STATIC_ASSERT(C_FALSE == false, C_CPP_false_equiv);
  STATIC_ASSERT(!C_TRUE == false, C_TRUE_not);
  STATIC_ASSERT(!true == C_FALSE, CPP_true_not);
  STATIC_ASSERT(!true == false, CPP_true_not);
  STATIC_ASSERT(!false == C_TRUE, CPP_false_not);
  STATIC_ASSERT(!false == true, CPP_false_not);
#endif // !defined(__cplusplus)
/* Values specifically for use with C_bool_t */
#define TRUE     true
#define FALSE    false

Basically, C++ is not guaranteed to be implemented as a char but it generally is, and almost certainly is and always will be when using GCC. We can even add the static asserts as above just for some peace of mind.

codebase/add_cpp.txt · Last modified: 2019/07/12 23:16 by vodur