Co się stanie, jeśli niezdefiniowane zachowanie C ++ spełnia zachowanie zdefiniowane w C?


10

Mam *.cppplik, który kompiluję za pomocą C ++ (nie kompilatora w języku C). Funkcja zawierająca opiera się na rzutowaniu (patrz ostatni wiersz), który wydaje się być zdefiniowany w C (popraw, jeśli się mylę!), Ale nie w C ++ dla tego specjalnego typu.

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

Skoro kompiluję to w pliku C ++, czy jest to teraz zdefiniowane czy niezdefiniowane zachowanie? A może powinienem przenieść to do *.cpliku, aby zdefiniować zachowanie?


1
Rozszerzenie pliku nie ma znaczenia; tylko jeśli skompilujesz go jako C lub C ++.
Fredrik,

1
Odpowiednie typy nie są dziedziczone od siebie i nie mają związku i że jest niezdefiniowana w C ++
Daniel Stephens

1
Zazwyczaj, jeśli plik ma .crozszerzenie, kompilator C jest wywoływany automatycznie.
Igor R.

1
Cały czas robię tę sztuczkę w kodzie C ++. Nie mam pojęcia, dlaczego to nie zadziała. Brakuje gdzieś nagłówka?
user4581301

3
@DanielStephens Ten program nigdy nie próbuje usuwać wskaźnika. Rzucanie samego siebie jest dozwolone , dereferencje - tylko czasami. Jeśli strona C poprawnie rzutuje wskaźnik z powrotem na prawdziwy typ, wszystko powinno być w porządku. Problemy z rzutowaniem mogą wystąpić, jeśli typy te mają różne wymagania dotyczące wyrównania.
user7860670,

Odpowiedzi:


6

Jest to zdefiniowane zarówno w C ++, jak i C. Nie narusza to ścisłych przepisów dotyczących aliasingu, ponieważ nie wyklucza wynikowego wskaźnika.

Oto cytat z C ++ (dzięki @interjay i @VTT), który pozwala na to:

Wskaźnik obiektu można jawnie przekonwertować na wskaźnik obiektu innego typu.

Oto cytat z C (dzięki @StoryTeller), który pozwala na to:

Wskaźnik do typu obiektu można przekonwertować na wskaźnik do innego typu obiektu.

Określają one, że jeden typ wskaźnika można przekonwertować na inny typ wskaźnika (a następnie opcjonalnie przekonwertować z powrotem) bez konsekwencji.

Oto cytat z POSIX, który pozwala na ten konkretny przypadek:

Struktura sockaddr_in służy do przechowywania adresów dla rodziny adresów internetowych. Wskaźniki tego typu będą rzutowane przez aplikacje na struct sockaddr * do użytku z funkcjami gniazd.

Ponieważ ta funkcja ( bind) jest częścią standardowej biblioteki C, cokolwiek dzieje się w środku (a konkretnie dereferencja wskaźnika rzutowanego na typ) nie ma niezdefiniowanego zachowania.


Aby odpowiedzieć na bardziej ogólne pytanie:

C i C ++ to dwa różne języki. Jeśli coś jest zdefiniowane w C, ale nie w C ++, jest zdefiniowane w C, ale nie w C ++. Żadna domniemana zgodność między dwoma językami tego nie zmieni. Jeśli chcesz użyć kodu dobrze zdefiniowanego w C, ale niezdefiniowanego w C ++, będziesz musiał użyć kompilatora C do skompilowania tego kodu.


1
@interjay Czy możesz to poprzeć cytatem ze standardu (C lub C ++ jest w porządku)?
SS Anne


1
@StoryTeller Dzięki. Zamiast tego dodano wersję HTTP.
SS Anne

2
Prawdopodobnie jest to wada standardu POSIX - drugi argument bindpowinien być a const void *, ale bindpoprzedza istnienie voidw języku C (i w ogóle C ++). W pewnym momencie zaktualizowali go, aby dodać const, ale nigdy nie naprawili podstawowego typu.
Chris Dodd

1
Mogę polecić tę rozmowę youtube.com/watch?v=_qzMpk-22cc Nadal nie jestem pewien, czy potwierdza ona odpowiedź, czy też faktycznie mówi coś przeciwnego: -o C ++ to koszmar .. lol
Daniel Stephens

-3

Wywołania między kodami C i C ++ wywołują Niezdefiniowane zachowanie z punktu widzenia odpowiednich standardów, ale większość platform określa takie rzeczy.

W sytuacjach, w których części standardu C lub C ++ oraz dokumentacja implementacji razem definiują lub opisują działanie, ale inne części określają je jako Niezdefiniowane, implementacje mogą przetwarzać kod w dowolny sposób, który najlepiej zaspokoi potrzeby klientów lub - jeśli są obojętni na potrzeby klientów - niezależnie od mody, którą uznają za stosowną. Fakt, że Standard traktuje takie kwestie jako będące poza ich jurysdykcją, nie implikuje żadnego osądu co do tego, kiedy i / lub w jaki sposób implementacje twierdzące, że są odpowiednie do różnych celów, powinny je w znaczący sposób przetwarzać, ale niektórzy opiekunowie kompilatorów zgadzają się z tym mitem.


Pierwszy akapit: „Wszystkie wywołania między kodem C i C ++ wywołują niezdefiniowane zachowanie” Nawet jeśli istnieje coś takiego jak „wywoływanie niezdefiniowanego zachowania” (którego nie ma), to nadal nie ma sensu.
Wyścigi lekkości na orbicie

Drugi akapit: nie mam pojęcia, co próbujesz powiedzieć.
Wyścigi lekkości na orbicie

@LightnessRacesinOrbit Myślę, że ta odpowiedź była wynikiem dodania do pytania znacznika [language-lawyer]. Teraz pomyślałem o tym lepiej (odpowiedzi wydają się zbyt dosłowne) i usunąłem go.
SS Anne,

1
@ JL2210 Nie sądzę, że to była twoja wina.
Wyścigi lekkości na orbicie
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.