LINUX.ORG.RU
ФорумTalks

С++ имеет синтаксис для некорректных функций

 


0

2

В С++ (даже 17) можно не писать return в функции, которая должна что-то возвращать. Это скомпилируется. Но в рантайме, при вызове этого метода прога упадет с кодом ошибки.

То есть, имеется специальный синтаксис для функций, про которые заранее на этапе компиляции известно, что они некорректные. Может ли здоровый человек такое придумать?

Вы там охренели? Это вообще нормально? Алло, не бросайте трубку.

★★★★☆
Ответ на: комментарий от stevejobs

U - unspecified.

В общем и целом, согласен, странное желание получить «рандомное» значение со стека или в регистре или ещё откуда.

Но, если экономить на спичках - можно например в функции с тремя выходами не тратить время на один, два или даже все три выхода, при каких то обстоятельствах.

Для тех кто не хочет, в каждой нормальной реализации есть способ сиё превратить в ошибку этапа компиляции.

То, что в gcc это по дефолту не ошибка, ну х3, почему-то так сделанно, я не настолько спец в байтолюбстве, что бы предполагать почему.

То, что в стандарте это не ошибка:

The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot.

pon4ik ★★★★★
()
Ответ на: комментарий от stevejobs

разные флаги могут действительно интерпретироваться по-разному, но -Wall -Werror это та комбинация, которая к проблемам приводит в 146% случаев

Нет, если ты это делаешь локально. Если ты это пихаешь в дистрибутив, то конечно приводит.

kirk_johnson ★☆
()

Причём не один такой синтаксис, чтож это делается-то такое.

int main(){
  auto f=(void(*)())0;
  f();
}

nvidia
()

Не любят C/C++ те, кто не знает их.

Deleted
()
Ответ на: комментарий от stevejobs

а должна быть ошибка времени компиляции

Даже, если уже написали:

g++ -Werror=return-type
clang++ -Werror=return-type

KennyMinigun ★★★★★
()

-Werror=return-type

имеется специальный синтаксис для функций, про которые заранее на этапе компиляции известно, что они некорректные

Если возвращаемое значение не используется, то усе корректно.

annulen ★★★★★
()
Ответ на: комментарий от kirk_johnson

Вот в Rust return обязателен.

В Rust есть unsafe, в котором я могу делать все, что захочу.

Напиши на unsafe Rust функцию, которая не возвращает значения, хотя должна.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

1) Может быть сложное ветвление с участием вызовов функций, даже неизвестных в текущем модуле

Такое ветвление сводится к комбинаторике из двух значений: true и false (т.е. N = 2) в степени количества ветвлений. Это худший случай. В процессе компилятор может еще довести, что некоторые выражения будут перманентно true или false. А также импликацию (зависимости) условий между собой.

Проблема только в inline assembly и функциях, которые должны быть обозначены [[noreturn]] но не обозначены: в таких случаях бывает невозможно доказать, что исполнение после таких секций кода не продолжается.

KennyMinigun ★★★★★
()
Ответ на: комментарий от KennyMinigun

Такое ветвление сводится к комбинаторике из двух значений: true и false (т.е. N = 2) в степени количества ветвлений. Это худший случай. В процессе компилятор может еще довести, что некоторые выражения будут перманентно true или false. А также импликацию (зависимости) условий между собой.

Ещё раз. Ветвление идёт в динамике. Компилятору может казаться, что возможен случай, когда все ветви, которые содержат return, не выстрелят. Хотя в рантайме этого никогда не произойдёт, и всегда сработает хотя бы один return. Это может быть очевидно программисту, и совершенно не очевидно компилятору.

Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Суть в том, что выстрелить себе в ногу, приложив усилия, можно довольно-таки легко практически везде. Игнорирование ворнингов компилятора — плохая затея.

kirk_johnson ★☆
()
Последнее исправление: kirk_johnson (всего исправлений: 1)
Ответ на: комментарий от kirk_johnson

выстрелить себе в ногу, приложив усилия, можно довольно-таки легко практически везде

В Си или Си++ услилия приходиться прикладывать, чтобы _не_ выстрелить себе в ногу. И обычно эти усилия недостаточны.

tailgunner ★★★★★
()

имеется специальный синтаксис для функций, про которые заранее на этапе компиляции известно, что они некорректные.

У GCC еще имеется аттрибут

[[noreturn]]
для функций, которые никогда не завершаются.

можно не писать return в функции, которая должна что-то возвращать. Это скомпилируется. Но в рантайме, при вызове этого метода прога упадет с кодом ошибки.

А может не упасть, у меня например не требовался результат такой функции, хоть она и должна была что-то возвращать - ничего не падало.

Плюс еще можно создавать виртуальные функции без указания типа

virtual myFunc();
тоже все будет компилироваться и работать, но GCC будет считать, что они имеют тип int.

SR_team ★★★★★
()
Ответ на: комментарий от bonta

Посмотри на стандартную библиотеку D и C++. Обе на шаблонах, шаблоны применяют примерно равные фичи (хотя в D шаблоны по сильнее), при этом в D сразу понятно, что там происходит, а в C++ приходится долго парсить код глазами.

SR_team ★★★★★
()
Ответ на: комментарий от RazrFalcon

Я не понимаю, к чему ты клонишь. Раст сам по себе — не панацея. Все равно требуется тестирование и багфикс. Насколько сильно экономитмя время еще предстоит посчитать.

kirk_johnson ★☆
()
Ответ на: комментарий от RazrFalcon

Да, только я немного напутал. Оказывается нужен флаг -fpermissive, но я не помню, что бы использовал его в проекте, где допускал такую ошибку. Впрочем он компилировался MinGW, мб там по дефолту такое для винды разрешили, следуя тенденциям MSVC

UPD: а возможно данный флаг CMake для Debug сборок дописывает

SR_team ★★★★★
()
Последнее исправление: SR_team (всего исправлений: 1)
Ответ на: комментарий от stevejobs

ну для этого компилятор должен доказать, что этого никогда не случится

Компилятор который может это доказать, должен иметь возможность полностью протестировать код в режиме эксплуатации, если бы такой компилятор существовал, то никто бы не писал юниттесты

SR_team ★★★★★
()
Ответ на: комментарий от i-rinat

А я использовал std::move для вектора, который является элементом структуры и в gcc всё нормально работало, а в msvs 2013 этот кусок работал иначе - вектор прсто копировался, но с новым адресом, а исходный вектор не очищался, как в случае с gcc

grem ★★★★★
()

зачем писать на прошлогодней версии стандарта, она недостаточно окаменевшая

Harald ★★★★★
()
Ответ на: комментарий от Crocodoom

И да и нет. Если подать на вход такой функции подобранные данные, то она вылетит с UB. ИМХО в таком случае в конце вставить assert(«unreachable»); и дать себе и компилятору спокойствие

KennyMinigun ★★★★★
()
Ответ на: комментарий от RazrFalcon

Не в GCC, а в C++11.

Если ничего не путаю, то VS2015 или VS2017 сказала мне, что такое она не знает, по этому решил указать компилятор

SR_team ★★★★★
()
Ответ на: комментарий от KennyMinigun

И да и нет. Если подать на вход такой функции подобранные данные, то она вылетит с UB. ИМХО в таком случае в конце вставить assert(«unreachable»); и дать себе и компилятору спокойствие

И да и нет.

Да, для многих таких функций будут существовать специальные кейсы, при которых возникнет UB, и лишь программист должен следить за тем, чтобы этих кейсов не было в вызывающем коде.

Нет, это не обязательно будет так. Возможны функции, на любых входных данных работающие без UB, при этом компилятор этот факт доказать не сможет, и будет ругаться. Примеры таких функций легко приводятся, но они не будут совсем уж тривиальными, поскольку тривиальные случаи современные компиляторы разбирать всё-таки научились.

Crocodoom ★★★★★
()
Ответ на: комментарий от kirk_johnson

Мораль в том, что тестировать наличие определённых проблем тупо не нужно. И как современный язык может быть менее эффективным чем окаменелость?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Мораль в том, что тестировать наличие определённых проблем тупо не нужно.

Каких, например? Тестировать return не нужно, достаточно собрать относительно новым компилятором с -Wall,-Werror. А фазер нужен в обоих случаях, потому что тот же treebitmap падает не от всякого ввода.

как современный язык может быть менее эффективным чем окаменелость?

А это вообще частныц случай NIH.

kirk_johnson ★☆
()
Ответ на: комментарий от kirk_johnson

Каких, например?

Память же.

А фазер нужен в обоих случаях, потому что тот же treebitmap падает не от всякого ввода.

Я хз о каком treebitmap идёт речь. Если в коде нет unsafe - то и тестировать там нечего. Разве что memory leak для Rc.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Память же.

Я ловлю в растовых либах сегфолты. Значит все-таки надо.

Если в коде нет unsafe - то и тестировать там нечего.

А если этот код зовет чужие либы? А если эти либы зовут?

Это типа как с питоном — вроде memory safety во все поля, однако половина питовоного кода зовет питоновые либы, которые внутри сишный код. И пошло-поехало.

kirk_johnson ★☆
()
Последнее исправление: kirk_johnson (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

Возможны функции, на любых входных данных работающие без UB, при этом компилятор этот факт доказать не сможет, и будет ругаться.

Да, убедил. Но хватит вставить в конце assert(0 && "unreachable") и компилятор ругаться перестанет

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от kirk_johnson

Я ловлю в растовых либах сегфолты

Ну про treebitmap понятно, но это всего одна либа, причем, судя по векторам сырых указателей и unsafe, написанная каким-то демоном скорости. Еще какие?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ну про treebitmap понятно, но это всего одна либа, причем, судя по векторам сырых указателей и unsafe, написанная каким-то демоном скорости. Еще какие?

https://medium.com/@shnatsel/how-rusts-standard-library-was-vulnerable-for-ye...

kirk_johnson ★☆
()
Ответ на: комментарий от kirk_johnson

Я читал это. Прекрасная причина избегать либ на unsafe Rust, вроде treebitmap. А ты назовешь вторую либу, в которой ловишь сегфолты? И третью, и далее.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Я читал это. Прекрасная причина избегать либ на unsafe Rust, вроде treebitmap.

В стандартной растовой библиотеке есть unsafe код. Предлагаешь работать с nostd?

А ты назовешь вторую либу, в которой ловишь сегфолты? И третью, и далее.

Понятия не имею, что там ещё сегфолтится, мне из сторонних нужно было только это. Но суть в чем — тебе все равно придется тестировать свой код, потому что чужие либы могут падать. Либо не использовать чужие либы и писать весь код самому. Но тогда тоже придется, потому что падать может сишная libc.

kirk_johnson ★☆
()
Ответ на: комментарий от tailgunner

ты намекаешь на безудержную крутость явы, в которой теперь нужно обновляться её раз в 6 месяцев, и соответственно -Wall -Werror неактуальны? Да, мы такие :))

к сожалению, пока яву полностью не перепишут на яве, и заодним все необходимые программы и либы - хотел бы да не могу последовать совету :(

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

ты намекаешь на безудержную крутость явы

в которой URL по IP сравнивали, ага.

kirk_johnson ★☆
()
Ответ на: комментарий от kirk_johnson

Если ты это пихаешь в дистрибутив, то конечно приводит.

я ничего не пихаю в дистрибутив. Я не пользуюсь компилятором из дистрибутива, а тащу свой. И библиотеками из дистрибутива тоже не пользуюсь - собираю всё локально и линкую вручную. Условно, всё что нужно от дистрибутива - наличие ядра и glibc, всё остальное я по необходимости сам притащу и соберу в рамках сборки софтины

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

я ничего не пихаю в дистрибутив. Я не пользуюсь компилятором из дистрибутива, а тащу свой. И библиотеками из дистрибутива тоже не пользуюсь - собираю всё локально и линкую вручную. Условно, всё что нужно от дистрибутива - наличие ядра и glibc, всё остальное я по необходимости сам притащу и соберу в рамках сборки софтины

В данном случае дистрибутив — тарболл с сорцами, которые собирают другие люди. Сорян, перегруженный термин.

kirk_johnson ★☆
()

А ещё есть

int i = 5; i = ++i + ++i;
Что сказать то хотел? Кресты это тот ЯП который позволяет тебе стрелять в ногу из дробовика, к дулу которого привязана граната.

peregrine ★★★★★
()
Ответ на: комментарий от stevejobs

У возвращаемого типа просто может не быть конструктора по умолчанию, что тогда возвращать будем?

Crocodoom ★★★★★
()

То есть, имеется специальный синтаксис для функций, про которые заранее на этапе компиляции известно, что они некорректные. Может ли здоровый человек такое придумать?

С - это макрос для ассемблера

CC - это объектизация макроса для ассемблера

оно не могло скомпилировать то, чего оно не понимает. следовательно - это ты не понимаешь, что пишешь.

PexuOne
()
Ответ на: комментарий от kirk_johnson

Если используете либы с unsafe - то может и надо.

А если этот код зовет чужие либы?

Можно проверить, используют ли они unsafe.

Я ловлю в растовых либах сегфолты.

«Я за два года использования rust не видел ни одного сегфолта. Значит не надо.» Выборка ни о чём.

RazrFalcon ★★★★★
()
Последнее исправление: RazrFalcon (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.