Was passiert, wenn undefiniertes C ++ - Verhalten mit C-definiertem Verhalten übereinstimmt?

10

Ich habe ein *.cpp Datei, die ich mit C ++ kompiliere (kein C-Compiler). Die enthaltende Funktion basiert auf einer Besetzung (siehe letzte Zeile), die in C definiert zu sein scheint (bitte korrigieren, wenn ich falsch liege!), Aber nicht in C ++ für diesen speziellen Typ.

[...] C++ code [...]

struct sockaddr_in sa = {0};
int sockfd = ...;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
bind(sockfd, (struct sockaddr *)&sa, sizeof sa);

[...] C++ code [...]

Ist dieses Verhalten jetzt definiert oder undefiniert, da ich es in einer C ++ - Datei kompiliere? Oder müsste ich dies in eine *.cDatei verschieben, um das Verhalten zu definieren?

Daniel Stephens
quelle
1
Die Dateierweiterung hat keine Bedeutung. Nur wenn Sie es als C oder C ++ kompilieren.
Fredrik
1
Die entsprechenden Typen werden nicht voneinander geerbt und haben keine Beziehung und das ist in C ++
Daniel Stephens
1
Wenn die Datei die .cErweiterung hat, wird der C-Compiler normalerweise automatisch aufgerufen.
Igor R.
1
Ich mache diesen Trick die ganze Zeit in C ++ - Code. Keine Ahnung, warum es bei Ihnen nicht funktioniert. Fehlt irgendwo ein Header?
user4581301
3
@DanielStephens Dieses Programm versucht niemals, den Zeiger zu dereferenzieren. Cast selbst ist erlaubt , Dereferenzierung - nur manchmal. Wenn die C-Seite den Zeiger korrekt auf den realen Typ zurückwirft, sollte alles in Ordnung sein. Probleme beim Gießen können auftreten, wenn diese Typen unterschiedliche Ausrichtungsanforderungen haben.
user7860670

Antworten:

6

Dies ist sowohl in C ++ als auch in C definiert. Es verstößt nicht gegen strenge Aliasing-Bestimmungen, da der resultierende Zeiger nicht dereferenziert wird.

Hier ist das Zitat aus C ++ (dank @interjay und @VTT), das dies ermöglicht:

Ein Objektzeiger kann explizit in einen Objektzeiger eines anderen Typs konvertiert werden.

Hier ist das Zitat von C (danke @StoryTeller), das dies ermöglicht:

Ein Zeiger auf einen Objekttyp kann in einen Zeiger auf einen anderen Objekttyp konvertiert werden.

Diese geben an, dass ein Zeigertyp ohne Konsequenz in einen anderen Zeigertyp konvertiert (und dann optional zurückkonvertiert) werden kann.

Und hier ist das Zitat von POSIX , das diesen speziellen Fall zulässt:

Die Struktur sockaddr_in wird zum Speichern von Adressen für die Internetadressfamilie verwendet. Zeiger dieses Typs werden von Anwendungen zur Strukturierung von sockaddr * zur Verwendung mit Socket-Funktionen gegossen .

Da diese Funktion ( bind) Teil der C-Standardbibliothek ist, weist alles, was im Inneren vor sich geht (insbesondere das Dereferenzieren des typgesteuerten Zeigers), kein undefiniertes Verhalten auf.


Um die allgemeinere Frage zu beantworten:

C und C ++ sind zwei verschiedene Sprachen. Wenn etwas in C definiert ist, aber nicht in C ++, ist es in C definiert, aber nicht in C ++. Keine implizite Kompatibilität zwischen den beiden Sprachen wird dies ändern. Wenn Sie Code verwenden möchten, der in C gut definiert, in C ++ jedoch nicht definiert ist, müssen Sie einen C-Compiler verwenden, um diesen Code zu kompilieren.

SS Anne
quelle
1
@interjay Kannst du das mit einem Zitat aus dem Standard belegen (entweder C oder C ++ ist in Ordnung)?
SS Anne
1
Dort gehen Sie port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7
StoryTeller - Unslander Monica
1
@ StoryTeller Danke. Stattdessen wurde jedoch die HTTP-Version hinzugefügt.
SS Anne
2
Dies ist wohl ein Defekt im POSIX-Standard - das zweite Argument bindsollte a sein const void *, geht jedoch bindder Existenz von voidin der C-Sprache (und der Existenz von C ++ überhaupt) voraus. Sie haben es irgendwann aktualisiert, um den Basistyp hinzuzufügen const, aber nie behoben.
Chris Dodd
1
Ich kann diesen Vortrag empfehlen. Youtube.com/watch?v=_qzMpk-22cc Ich bin mir immer noch nicht sicher, ob er die Antwort bestätigt oder ob er tatsächlich das Gegenteil sagt: -o C ++ ist ein Albtraum. Lol
Daniel Stephens
-3

Aufrufe zwischen C- und C ++ - Code rufen aus Sicht der jeweiligen Standards alle undefiniertes Verhalten auf, aber die meisten Plattformen spezifizieren solche Dinge.

In Situationen, in denen Teile des C- oder C ++ - Standards und die Dokumentation einer Implementierung zusammen eine Aktion definieren oder beschreiben, andere Teile sie jedoch als undefiniert charakterisieren, können Implementierungen Code auf eine Weise verarbeiten, die den Anforderungen ihrer Kunden am besten entspricht, oder - wenn dies der Fall ist Kundenbedürfnisse sind gleichgültig - egal welche Mode sie für richtig halten. Die Tatsache, dass der Standard solche Angelegenheiten als außerhalb ihrer Zuständigkeit liegend betrachtet, impliziert keine Beurteilung darüber, wann und / oder wie Implementierungen, die die Eignung für verschiedene Zwecke beanspruchen, sie sinnvoll verarbeiten sollten, aber einige Compiler-Betreuer unterschreiben einen Mythos, dass dies der Fall ist.

Superkatze
quelle
Erster Absatz: "Aufrufe zwischen C- und C ++ - Code rufen alle undefiniertes Verhalten auf" Auch wenn es so etwas wie "undefiniertes Verhalten aufrufen" gab (was es nicht gibt), macht dies immer noch keinen Sinn.
Leichtigkeitsrennen im Orbit
Zweiter Absatz: Keine Ahnung, was Sie sagen wollen.
Leichtigkeitsrennen im Orbit
@LightnessRacesinOrbit Ich denke, diese Antwort war das Ergebnis des Hinzufügens des Tags [Sprachanwalt] zur Frage. Ich habe jetzt besser darüber nachgedacht (die Antworten sind in der Regel viel zu wörtlich) und es entfernt.
SS Anne
1
@ JL2210 Ich glaube nicht, dass es deine Schuld war.
Leichtigkeitsrennen im Orbit