Что происходит, если неопределенное поведение C ++ соответствует определенному поведению C?


10

У меня есть *.cppфайл, который я компилирую с C ++ (не компилятор C). Содержащая функция опирается на приведение (см. Последнюю строку), которое, кажется, определено в C (пожалуйста, исправьте, если я ошибаюсь!), Но не в C ++ для этого специального типа.

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

Поскольку я компилирую это в файл C ++, это теперь определенное или неопределенное поведение? Или мне нужно переместить это в *.cфайл, чтобы определить поведение?


1
Расширение файла не имеет значения; только если вы компилируете его как C или C ++.
Фредрик

1
Соответствующие типы не наследуются друг от друга и не имеют отношения, и это не определено в C ++
Даниэль Стивенс

1
Как правило, если файл имеет .cрасширение, компилятор C вызывается автоматически.
Игорь Р.

1
Я делаю эту уловку все время в коде C ++. Не знаю, почему это не сработает для вас. Отсутствует заголовок где-нибудь?
user4581301

3
@DanielStephens Эта программа никогда не пытается разыменовать указатель. Само бросание разрешено , разыменование - только иногда. Если сторона C правильно возвращает указатель на реальный тип, тогда все должно быть хорошо. Проблемы с приведением могут возникнуть, если эти типы имеют различные требования выравнивания.
user7860670

Ответы:


6

Это определено как в C ++, так и в C. Это не нарушает строгих правил псевдонимов, поскольку не разыменовывает результирующий указатель.

Вот цитата из C ++ (благодаря @interjay и @VTT), которая позволяет это:

Указатель на объект может быть явно преобразован в указатель на объект другого типа.

Вот цитата из C (спасибо @StoryTeller), которая позволяет это:

Указатель на тип объекта может быть преобразован в указатель на другой тип объекта.

Они указывают, что один тип указателя может быть преобразован в другой тип указателя (и затем необязательно преобразован обратно) без последствий.

А вот цитата из POSIX, которая позволяет этот конкретный случай:

Структура sockaddr_in используется для хранения адресов для семейства интернет-адресов. Указатели на этот тип должны быть приведены приложениями к структуре sockaddr * для использования с функциями сокетов.

Так как эта функция ( bind) является частью стандартной библиотеки C, все, что происходит внутри (в частности, разыменование приведенного к типу указателя), не имеет неопределенного поведения.


Чтобы ответить на более общий вопрос:

C и C ++ - два разных языка. Если что-то определено в C, но не в C ++, это определяется в C, но не в C ++. Никакая подразумеваемая совместимость между этими двумя языками не изменит это. Если вы хотите использовать код, который четко определен в C, но не определен в C ++, вам придется использовать компилятор C для компиляции этого кода.


1
@interjay Можете ли вы подтвердить это цитатой из стандарта (C или C ++ хорошо)?
SS Anne


1
@StoryTeller Спасибо. Вместо этого добавлена ​​версия HTTP.
SS Anne

2
Возможно, это является дефектом в стандарте POSIX - вторым аргументом bindдолжно быть a const void *, но оно bindпредшествует существованию языка voidC (и вообще C ++). Они обновили его в какой-то момент, чтобы добавить const, но не исправили базовый тип.
Крис Додд

1
Я могу порекомендовать этот доклад youtube.com/watch?v=_qzMpk-22cc. Я до сих пор не уверен, подтвердит ли он ответ или действительно говорит обратное: -o C ++ - это страшный сон .. lol
Дэниел Стивенс

-3

Все вызовы между кодом C и C ++ вызывают неопределенное поведение с точки зрения соответствующих стандартов, но большинство платформ определяют такие вещи.

В ситуациях, когда части стандарта C или C ++ и документация реализации вместе определяют или описывают действие, но другие части характеризуют его как неопределенный, реализации разрешается обрабатывать код любым способом, который лучше всего отвечает потребностям их клиентов или - если они безразличны к потребностям клиентов - независимо от того, что они считают подходящим. Тот факт, что Стандарт рассматривает такие вопросы как находящиеся вне их юрисдикции, не подразумевает какого-либо суждения относительно того, когда и / или как реализации, требующие пригодности для различных целей, должны обрабатывать их осмысленно, но некоторые сопровождающие компилятора подписываются на миф о том, что он делает.


Первый абзац: «Все вызовы между кодом C и C ++ вызывают неопределенное поведение». Даже если была такая вещь, как «вызов неопределенного поведения» (чего нет), это все равно не имеет смысла.
Гонки

Второй абзац: не знаю, что вы пытаетесь сказать.
Гонки

@LightnessRacesinOrbit Я думаю, что этот ответ был результатом моего добавления тега [language-lawyer] к вопросу. Теперь я думаю об этом лучше (ответы, как правило, слишком буквальные) и удалил его.
SS Anne

1
@ JL2210 Не думаю, что это твоя вина.
Гонки
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.