Forum: PC-Programmierung C/C++ mixen -> "conflicting C language linkage declaration"


von Vincent H. (vinci)


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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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

von Vincent H. (vinci)


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...

von Jim M. (turboj)


Lesenswert?

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.

von Vincent H. (vinci)


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.

: Bearbeitet durch User
von Rolf M. (rmagnus)


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.

: Bearbeitet durch User
von Vincent H. (vinci)


Lesenswert?

Danke für die Erklärung. Extern "C" interessiert mich eh nicht, das 
passiert in dem Fall durch externe Libs...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.