16

I'm writing a c++ library that exposes some functions which are used only by C# code. However, as I accidently mistyped the paramter, I found that this code can be succesfully compiled and linked even without any warning as long as I don't use the (not mistyped version) function in the cpp file.

struct Dummy { int a; double b; };
extern "C" void SetArray(Dummy* x, int cnt);
void SetArray(Dummy x, int cnt)
{
    // a TODO placeholder.
}

How can I let compiler throw an error or a warning for this case? The compiler option -Wall is set but there's still no warning. Using tdmgcc 5.1.0.

karatoga
  • 513
  • 4
  • 14

2 Answers2

18

You can make some assertion that will fail if function is overloaded:

static_assert(::std::is_same_v<void (Dummy *, int), decltype(SetArray)>);

error: decltype cannot resolve address of overloaded function

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • It works! Thanks. Although I'm using C++11 and have to find another way similar to that... – karatoga Aug 03 '18 at 10:33
  • 3
    @Apliex-Ddr To work with c++11 this snippet requires only a few changes: use of `::std::is_same` and mandatory assertion message. – user7860670 Aug 03 '18 at 10:42
  • Wait, where do you put that assertion? IINM the compiler should already prevent you from overloading the function once it has seen the `extern "C"` declaration... – Quentin Aug 03 '18 at 12:01
  • @Quentin: Are you absolutely sure about that? I can imagine wanting to expose one overload to C, but keep the convenience of other overloads in C++. Now, I would use namespaces and separate C and C++ headers, effectively nullifying this situation, but I don't see why you could not provide a non-`extern "C"` overload of an `extern "C"` function. – rubenvb Aug 03 '18 at 12:18
  • @rubenvb I just tested it on Coliru and indeed you can overload `extern "C"` functions just fine. I'm confused. – Quentin Aug 03 '18 at 12:24
  • @Quentin You weren't entirely imagining things. See my answer. –  Aug 03 '18 at 12:53
  • This can be applied for all cases, not just extern C. (right?) – user202729 Aug 03 '18 at 16:02
  • I'd make it signature-agnostic. `!std::is_void_v` is just as good, and has less characters to type. – HolyBlackCat Aug 03 '18 at 20:57
13

You can include extern "C" in the definition as well as the declaration.

struct Dummy { int a; double b; };
extern "C" void SetArray(Dummy* x, int cnt);
extern "C" void SetArray(Dummy x, int cnt)
{
    // a TODO placeholder.
}

Quentin's comment on VTT's answer was halfway there: it's not that C functions cannot be overloaded, it's that C functions cannot be overloaded with other C functions. The compiler will enforce this, but it can only do so if you explicitly specify you want a C function in both declarations.

  • Possible justification for this behaviour: to the linker, both C structs in your example will have the same name (hence you have conflicting definitions), whereas the C++ struct in the OP's example will have a mangled name which is different from the C structure name. – grahamj42 Aug 03 '18 at 16:21
  • @grahamj42: I saw this in a header file: `#ifdef __cplusplus extern "C" long strtol(const char *input, const char **endptr, int base); extern "C" long strtol(char *input, char **endptr, int base); #else long strtol(const char *input, char **endptr, int base); #endif` – Joshua Aug 03 '18 at 18:24
  • @Joshua That's problematic for other reasons too (using non-reserved names). Where did you see that? –  Aug 03 '18 at 19:47
  • 1
    @hvd: In the compiler's `string.h` – Joshua Aug 03 '18 at 20:40
  • @Joshua That part was obvious. Which compiler? –  Aug 03 '18 at 21:00
  • @hvd: Borland C++ 4.5 – Joshua Aug 03 '18 at 21:22
  • @Joshua That's so old it predates the C++ standard though. –  Aug 03 '18 at 21:36