LINUX.ORG.RU

Мгновенный возврат в main из вложенных функций. Вопрос по select()

 , ,


0

2

Добрый день. Интересует решение на C/C++ (от платформы, надеюсь, это не зависит)

Допустим, у нас есть main() из которого вызывается функция А, из неё В, из неё С и т.д. Вопрос: как, не проходя в обратном порядке (из последней вернуться в С, из неё в В, из неё в А и только потом вернуться в main()), сразу вернуться в main()?


Еще один вопрос, связанный с сокетами:

Вот, к примеру, функция select() возвращает множество сокетов, в которых есть данные для чтения, множество сокетов с ошибками и множество сокетов, ожидающих запись. С первыми двумя всё понятно, сначала данных и ошибок не было, тут они появились и select() нам их возвращает. А вот с третьим совсем непонятно. Как может сокет ожидать записи, если пишем мы и мы решаем, когда хотим писать, а когда нет.

Можно объяснить, что здесь подразумевается под множеством сокетов, ожидающих записи, и как оно работает?

Как может сокет ожидать записи, если пишем мы и мы решаем, когда хотим писать, а когда нет.

Объём буфера записи у сокета конечный. Если ты этот буфер забьёшь, следующая запись может заблокироваться на время, пока данные из буфера не уйдут в сеть. Select тебе сообщает, что у сокета в буфере записи появилось место.

i-rinat ★★★★★ ()

1 goto. Пожалуй единственное оправданное применение, если это действительно надо, но я бы всё равно не рекомендовал так делать, выход стоит копейки, а goto портит код очень сильно.

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

peregrine ★★★★★ ()

А в каких языках так можно портабельно делать?

pon4ik ★★★★★ ()

не проходя в обратном порядке

Смотря, что под этим понимать. Похоже на кейс для исключений.

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

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

xpahos ★★★★★ ()

Как может сокет ожидать записи, если пишем мы и мы решаем, когда хотим писать, а когда нет.

Не знаю о чем ты, но не ты решаешь когда хочешь писать, а ОС. Есть как минимум half-closed сокеты. Но это все не совсем про select.

xpahos ★★★★★ ()
Последнее исправление: xpahos (всего исправлений: 1)

Допустим, у нас есть main() из которого вызывается функция А, из неё В, из неё С и т.д. Вопрос: как, не проходя в обратном порядке (из последней вернуться в С, из неё в В, из неё в А и только потом вернуться в main()), сразу вернуться в main()?

Тут надо читать «C++ exceptions».

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

longjump в C++ имеет несколько иное поведение и он будет анвиндить стэк

Шо? Это с каких это пор longjmp раскручивает стек?

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

@i-rinat спасибо, всё понял

@pon4ik хорошо, тогда вопрос в контексте Linux

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

@DllMain штука интересная, но вот фраза «transferring execution from one function to a predetermined location in another function» всё портит, ведь функция main() идет самой последней в коде на C/C++. Или я чего-то путаю? При попытках запустить из main() функцию, написанную после неё, кидает ошибку, мол функция не определена.

Или можно как-нибудь объявить функцию до main(), реализовать после и потом уже получиться прыгнуть в main?


Просто помню какое-то обсуждение людей по этому поводу, там они сошлись на каком-то решении, но вот помню только факт, что и как забыл, а вот сейчас интересно стало. И вот не могу найти его.

Architector ()
Последнее исправление: Architector (всего исправлений: 2)
Ответ на: комментарий от xpahos

Когда я хочу писать, а когда нет - решаю я и только я.

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

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

Так будешь со своим ядром разговаривать, когда его спроектируешь и реализуешь.

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

хорошо, тогда вопрос в контексте Linux

Хорошо, какие ещё языки так умеют в gnu/linux или любом другом рантайме поверх abi интерфейсов linux?

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

И что бы два раза не ходить - под какую аппаратную платформу.

pon4ik ★★★★★ ()

и вот ты выпрыгнул в main. Видимо следующим вопросом будет как запрыгнуть назад, в select?)

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

какие ещё языки так умеют

Я про это и спрашиваю, а точнее про то, возможно ли вообще это сделать. А C++ здесь для того, чтобы была какая-то конкретика.

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

Architector ()
Ответ на: комментарий от zudwa

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

Architector ()

как, не проходя в обратном порядке (из последней вернуться в С, из неё в В, из неё в А и только потом вернуться в main()), сразу вернуться в main()?

Ты исключения хочешь?

Очень плохая идея. Не нужно так делать.

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

Не надо это здеь читать. Исключения для иключительных ситуаций, а не для flow control.

ТС’у - чини архитектуру, Архитектор.

anonymous ()
Ответ на: комментарий от Architector

Пример вышеозвученного сценария для интерпретируемого языка сможешь привести?

А реальный кейс, когда это нужно?

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

Если что - я просто об ограничениях goto писал. А по теме - я за исключение, если уж есть нужда

DllMain ()
Ответ на: комментарий от Architector

Ты решаешь когда кнопку нажать, чтобы посты на форумах писать. А вот write уже вернет тебе что-нибудь вроде EAGAIN, когда ты попытаешься записать что-то больше SO_SNDBUF.

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

ибо сам goto не прокатит

Ты недооцениваешь мою глупость мощь!

#include <stdio.h>
#include <stdlib.h>

void innermost(void *a) {
  puts("    innermost enter");
  if (a) goto *a;
  puts("    innermost exit");
}

void inner(void *a) {
  puts("  inner enter");
  innermost(a);
  puts("  inner exit");
}

int main(void) {
  puts("main enter");
  inner(0);
  puts("main exit");

  puts("");

  puts("main enter");
  inner(&&label);
label:
  puts("main exit");
  return exit(0), 0;
}
$ gcc but_why.c && ./a.out 
main enter
  inner enter
    innermost enter
    innermost exit
  inner exit
main exit

main enter
  inner enter
    innermost enter
main exit
i-rinat ★★★★★ ()
Ответ на: комментарий от WitcherGeralt

Это ты ещё не видел, что со стеком происходит.

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

Если ты про g++ в Си++-режиме, то он съест. Если ты про стандарт языка, то и в Си так нельзя, не говоря уже о Си++.

i-rinat ★★★★★ ()

Exception

Допустим, у нас есть main() из которого вызывается функция А, из неё В, из неё С и т.д. Вопрос: как, не проходя в обратном порядке (из последней вернуться в С, из неё в В, из неё в А и только потом вернуться в main()), сразу вернуться в main()?

Это называет исключение - exception

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

Ёёёё...
Убери это и никому не показывай! Особенно неподготовленным умам.

Kroz ★★★★★ ()

1 - setjmp/longjmp но уверен ли ты что хочешь этого?

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

Или можно как-нибудь объявить функцию до main(), реализовать после и потом уже получиться прыгнуть в main?

man gcc constructor attribute

но это gcc-specific.

Dark_SavanT ★★★★★ ()
Ответ на: Exception от Kroz

Re: Exception

Триста тридцать пять…

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

Если ты про g++ в Си++-режиме, то он съест. Если ты про стандарт языка, то и в Си так нельзя, не говоря уже о Си++.

мой не ест.

test.cpp:70:10: error: indirect goto in function with no address-of-label expressions

alysnix ★★ ()
Ответ на: удаленный комментарий

Любители сижки продолжают переизобретать исключения и прочие удобства, которые в нормальных языках (rust) существуют уже давно.

исключения существовали задолго до руста, и будут существовать после него.

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

мой не ест.

А ты уверен, что твой g++ это не clang++? Потому что в исходниках GCC я не нашёл упоминания «indirect goto in function with no address-of-label expressions», зато нашёл в Clang.

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

В Visual С++ тоже есть constructor attribute аналог

#if defined (_MSC_VER) // MSVC
    #pragma section(".CRT$XCU",read)
    #define INITIALIZER_(FUNC,PREFIX) \
        static void FUNC(void); \
        __declspec(allocate(".CRT$XCU")) void (*FUNC##_)(void) = FUNC; \
        __pragma(comment(linker,"/include:" PREFIX #FUNC "_")) \
        static void FUNC(void)
    #ifdef _WIN64
        #define INITIALIZER(FUNC) INITIALIZER_(FUNC,"")
    #else
        #define INITIALIZER(FUNC) INITIALIZER_(FUNC,"_")
    #endif
#elif defined (__GNUC__) // GCC, Clang, MinGW
    #define INITIALIZER(FUNC) \
        static void FUNC(void) __attribute__((constructor)); \
        static void FUNC(void)
#else
    #error The CS50 library requires some compiler-specific features, \
           but we do not recognize this compiler/version. Please file an issue at \
           https://github.com/cs50/libcs50
#endif

Все как в старой-доброй сижке – адская мешанина из ifdef’ов и компилятороспецифичных макросов, а в конце еще и типичный #error если ты вдруг посмел использовать один из компиляторов не предусмотренных дядей сверху. Упаси нас, Раст, от этого ада.

Разорванный Флакон

anonymous ()
Ответ на: комментарий от alysnix

destroys objects with automatic duration any non-trivial destructors … undefined behavior

Ты ведь понимаешь, что это крестовый умный способ сказать, что просто нихрена не делается, и семантически это совпадает с описанным?

anonymous ()

как, не проходя в обратном порядке (из последней вернуться в С, из неё в В, из неё в А и только потом вернуться в main()), сразу вернуться в main()?

Как вариант, можешь пробросить континуацию майна до C, и там ее навсегда вызвать. То есть пишешь функцию int main_cont() и передаешь ее вниз по стеку вызовов. В ф-ии C делаешь exit(main_cont()); там где надо. Если нужен контекст пробрасывай через глоб.перем., доп.аргумент, либо замыканием. Если континуация одна, то можно не передавать, а захардкодить ее прямо в C.

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

А ты уверен, что твой g++ это не clang++? Потому что в исходниках GCC я не нашёл упоминания «indirect goto in function with no address-of-label expressions», зато нашёл в Clang.

а, да…у меня стоял цланг. а gcc, сьел запросто

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

Это говно состоит из ворованной обгрызанной семантике С++(в том числе и raii), но raii не существуют без исключений. И даже эти огрызки в этом дерьме там существуют лишь потому, что это базовая семантика и в llvm.

По этой причине срочно нужно было как-то объяснять хомячью то, почему в этом дерьме есть исключения. Так и родились паники. На самом деле это просто ворованные из C++ механизмы по дефолту существующие в llvm. И т.к. хомячьё не осилило реализовать исключения полноценно - пришлось искать оправдания.

Поэтому, меньше жри пропаганду и побольше изучай матчасть. А то окажется, что шутка не совсем шутка и можно опозориться.

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

Царь, ты как всегда непробиваем. То, что панику можно использовать как исключения, не придает ей той же семантики, которую имеют исключения в С++.

Держи еще один тейк (кстати, ты не ответил за свое неумение читать в прошлый раз): ни один человек не оспаривает мощность С++. Речь идет о том, что большинство задач, решаемых С++, отлично решается другими языками, пусть и более слабыми, причем с гораздо меньшими трудозатратами.

Чтобы не плодить оффтопик, если решишь ответить, отвечай в своем канале в телеге.

Siborgium ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.