C/C++ mixen -> "conflicting C language linkage declaration"

OP #7094364
Lesenswert?

Grüß euch

Ich hab scheinbar den Präprozessor und das __cplusplus Macro noch nicht 
so verstanden wie ich dachte. Kann mir jemand erklären was in folgendem 
Beispiel passiert:
1
// config.h
2
#pragma once
3
#if defined(__cplusplus)
4
namespace a {
5
inline constexpr auto v = 42;
6
}  // namespace a
7
namespace b {
8
inline constexpr auto v = 41;
9
}  // namespace b
10
#endif
1
// c_header.h
2
#pragma once
3
#if defined(__cplusplus)
4
extern "C" {
5
#endif
6
#include "config.h"
7
#if defined(__cplusplus)
8
}
9
#endif
1
// cpp_header.hpp
2
#pragma once
3
#include "c_header.h"
1
// main.cpp
2
#include "cpp_header.hpp"
3
int main() {}

Der Einfachheit halber auch nochmal auf github:
https://github.com/higaski/Mixing_C_Cpp

GCC (12.1.0) compiliert zwar durch, jedoch mit der im Titel erwähnten 
Fehlermeldung.
Clang (13.0.1) weigert sich gleich komplett den Code zu übersetzen und 
meint es handelt sich um eine Redefinition.
Ich dachte eigentlich dass man via __cplusplus geschützten Code und 
Header die jenen enthalten beliebig "stacken" kann.
OP #7094376
Lesenswert?

Niklas G. schrieb:
> Variablen in namespaces und inline Variablen kann man nicht extern "C"
> machen. Wie soll man da auch aus C drauf zugreifen können?

Gar nicht, nur was hat das mit der Frage zu tun? Ich würd gern wissen 
weshalb der Code oben nicht compiliert oder warnings produziert? 
Außerdem ist das Verhalten der Compiler nicht konsistent.

Folgendes compiliert zum Beispiel unter Clang (in einer TU):
1
#if defined(__cplusplus)
2
extern "C" {
3
#endif
4

5
#ifdef __cplusplus
6
namespace a {
7
constexpr auto v = 42;
8
}
9

10
namespace b {
11
constexpr auto v = 42;
12
}
13
#endif
14

15
#ifdef __cplusplus
16
}
17
#endif

In GCC gibts erneut die Warnung...
OP #7094389
Lesenswert?

Jim M. schrieb:
> Schau Dir mal den C Präprozessor Output (gcc -E) in obigen Fällen an.
>
> Die "config.h" ist im Falle "C Compiler ohne C++" total leer.

Ja das hät ich auch erwartet. Der C Compiler compiliert Sourcen mit dem 
Header auch ohne Probleme.

Und mein Beispiel eben compiliert unter Clang doch nicht, zumindest 
nicht mit inline Keyword...
1
#if defined(__cplusplus)
2
extern "C" {
3
#endif
4

5
#ifdef __cplusplus
6
namespace a {
7
inline constexpr auto v = 42;
8
}
9

10
namespace b {
11
inline constexpr auto v = 42;
12
}
13
#endif
14

15
#ifdef __cplusplus
16
}
17
#endif

Soweit ich das bis jetzt kapiert hab dürfte Clang hier schon recht 
haben. Die Variablen bekommen C-Linkage und es kommt tatsächlich zu 
einer Redefinition. Sehr böse...

/edit
Und noch gemeiner dass GCC hier lediglich warnt.

/edit2
Durch das ändern von inline constexpr in static constexpr lässt sich das 
Problem umgehen.
#7094474
Lesenswert?

Niklas G. schrieb:
> Variablen in namespaces und inline Variablen kann man nicht extern "C"
> machen. Wie soll man da auch aus C drauf zugreifen können?

Variablen in Namespaces kann man sehr wohl extern "C" machen. Der 
Namespace wird in diesem Fall im Bezug auf die Linkage ignoriert, und 
zwar sowohl in C, als auch in C++. Und das führt dann dazu:

Vincent H. schrieb:
> Clang (13.0.1) weigert sich gleich komplett den Code zu übersetzen und
> meint es handelt sich um eine Redefinition.

a::v und b::v sind schlicht die selbe Variable, da sie extern "C" sind.

Vincent H. schrieb:
> Durch das ändern von inline constexpr in static constexpr lässt sich das
> Problem umgehen.

Wenn sie static sind, haben sie ja auch keine external linkage mehr. 
Dann bringt's aber auch nichts, sie extern "C" zu machen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren