AleksBak 0 7 апреля, 2016 Опубликовано 7 апреля, 2016 · Жалоба Вот если я скажем делаю так (использую NetConn API): struct netconn *conn, *newconn; err_t err, accept_err; conn = netconn_new(NETCONN_TCP); while (1) { if (conn != NULL) { err = netconn_bind(conn, NULL, 7000); if (err == ERR_OK) { netconn_listen(conn); while (1) { accept_err = netconn_accept(conn, &newconn); /* Process the new connection. */ if (accept_err == ERR_OK) { ... } } } else { netconn_delete(conn); } } } Т.е. все "по мануалу" и вопросов тут нет. Но вот вопрос такой тут - в функцию netconn_accept(conn, &newconn); я передал указатель на newconn, а эта функция в ответ обновила его значением указателя на свою локальную переменную (как я понял). Т.е. др. словами говоря - она создала внутри у себя какую-то локальную переменную, а потом второй параметр этой самой функции обновила уже новым значением указателя на эту переменную. И как теперь это понимать - ведь та локальная переменная существует в куче, но может же в любой момент времени быть затерта. Т.е. все работает как бы "до поры - до времени" так получается? Пока не "затрется случайно" та локальная переменная другим чем-то в ОЗУ. Или я не так понял? Или тут эта переменная newconn как бы "неполноценно" используется и в ней только что-то одно временно берется и потому все безопасно работает? Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 7 апреля, 2016 Опубликовано 7 апреля, 2016 · Жалоба Я после того как написал свой вопрос все переживал, что не привел код самой функции netconn_accept() из стека LwIP и думал "вот люди будут меня ругать, что не показал ее код тоже", а оказывается никто не ответил даже еще. Вот сама функция netconn_accept из стека (в ней я убрал все некомпилирующиеся куски кода из-за условной компиляции чтобы не загромождать лишним кодом, а также добавил комментарий в том месте где ожидается получение семафора - см. код): err_t netconn_accept(struct netconn *conn, struct netconn **new_conn) { struct netconn *newconn; err_t err; LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); *new_conn = NULL; LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;); err = conn->last_err; if (ERR_IS_FATAL(err)) { /* don't recv on fatal errors: this might block the application task waiting on acceptmbox forever! */ return err; } /* т.к. 3-й параметр тут - timeout равен 0, то ждем бесконечно долго прихода message (так сделано в этой функции): */ sys_arch_mbox_fetch(&conn->acceptmbox, (void **) &newconn, 0); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); if (newconn == NULL) { /* connection has been aborted */ NETCONN_SET_SAFE_ERR(conn, ERR_ABRT); return ERR_ABRT; } *new_conn = newconn; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; } Обратите внимание на строку №<последняя строка - 3> тут - вот это и есть, то о чем я писал: *new_conn = newconn; т.е. приравнивается значение указателя из 2-го параметра значению указателя на локальную переменную структуры! Т.е. вопрос такой в итоге (извините, что сложно может написал до этого) - "Почему эта функция netconn_accept() из стека LwIP возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_NB 0 7 апреля, 2016 Опубликовано 7 апреля, 2016 · Жалоба Т.е. вопрос такой в итоге (извините, что сложно может написал до этого) - "Почему эта функция netconn_accept() из стека LwIP возвращает фактически указатель на свою локальную переменную?? Это правильно??" Спасибо. Она возвращает значение этой локальной переменной, а не указатель на нее Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Она возвращает значение этой локальной переменной, а не указатель на нее Нет не так. В эту функцию передается указатель на указатель - переменная new_conn и вот такое объявление ее как параметра функции: struct netconn **new_conn Внутри функции объявляется свой, локальный указатель на структуру newconn (может тут кроется ответ на загадку т.к. при его объявлении выделяется память из какой-то "особой" памяти самого стека LwIP? но это бред все-таки). Далее, под конец, мы видим, что: *new_conn = newconn; т.е. все как писал - по переданному указателю на указателю пишется значение своего локального указателя. Тут даже и пояснять мне уже не нужно т.к. может запутываю в итоге и непонятен будет вопрос - все и так видно как на ладони. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба ...по переданному указателю на указателю пишется значение своего локального указателя. Так в чем опасность? Сами же написали значение, не указатель. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Так в чем опасность? Сами же написали значение, не указатель. Возвращается обратно значение указателя. А через это значение указателя далее в коде (в вызвавшей функции) идут обращения к той структуре (см. код). Т.е. где-то в куче она все еще есть пока что! Т.е. обращаемся к ней, а она находится в куче (или же в "бывшей" памяти стека) в это время. Вот так все и выходит. Теперь надеюсь понятно да? Если теперь опять какую-то (любую) функцию вызовем, то она легко может затереть значение той переменной в RAM, а мы по-прежнему будем думать, что то значение валидное внутри вызывающей основной функции. У меня еще есть объяснение, что вот с точки зрения применения ОС (NetConn API только для ОС написано) тут вроде ничего "страшного" нет. Вроде бы! У каждой задачи свой стек и т.д. И поэтому эти стеки задач существуют в раздельности и нерушимы. Но на самом деле - если, как только что написал, снова вызовем какую-то любую функцию то значение структуры все равно покоцается в этом "нерушимом" стеке. Или опять-таки я не прав и все не так? И вообще зачем они так это сделали по-дурацки (так выходит)? Зачем этот LwIP себе еще отдельные порции RAM "отгребает" при инициализации? И не малые причем! Это все отдельные и другие вопросы (их много вообще-то). Но пока хотя бы на этот вопрос в теме кто бы ответил. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба AleksBak: Представьте, Вам нужно написать функцию, которая будет внутри использовать malloc для выделения памяти. Но указатель на выделенную память нужно вернуть не через возвращаемое значение, а через один из аргументов функции. Подумайте, как бы Вы написали такую функцию -- уверен, это поможет найти ответ на Ваш вопрос :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба ... Представьте, Вам нужно написать функцию, которая будет внутри использовать malloc для выделения памяти. ... malloc-ом я память выделяю и сразу же дальше использую внутри функции. А тут в одной функции выделена память, создана переменная в этой памяти и возвращается указатель на эту созданную переменную. А в вызвавшей функции мы продолжаем обращаться к той переменной несмотря на то, что она когда-то была простой локальной переменной в той функции, а не у нас и не здесь. Так теперь понятно? Это же разные вещи тут. Еще вот объяснение у меня есть - может в этом LwIP не настолько все просто сделано и этот указатель, который возвращается указывает на какую-то особую "LwIP"-овскую суперпамять внутри RAM? Но что-то по коду такого не видно тут такого абсолютно. Надо бы отладчиком посмотреть, что и как когда будет возможность. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба ...Так теперь понятно?... Мне точно понятно, что Вы прочитали не всё моё сообщение :) Но указатель на выделенную память нужно вернуть не через возвращаемое значение, а через один из аргументов функции. Т.е. цель -- написать функцию-обёртку для malloc, которая будет не просто использовать память, а возвращать её наружу (и именно через аргумент). Всё-таки советую Вам написать такую функцию :) А уже потом, если вопросы всё-таки останутся, то обсудить их. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба ...написать функцию-обёртку для malloc, которая будет не просто использовать память, а возвращать её наружу (и именно через аргумент). Всё-таки советую Вам написать такую функцию :).... Да я Вам сразу отвечу как бы все это было бы. Что тут размышлять как и чего. Выделил память, ничего бы с ней не делал дальше и тут же вернул бы на нее указатель. И Все. А тут - выделяется память, в ней создается переменная, что-то с ней делается, а потом возвращается указатель на ту переменную, а далее мы у себя опять обращаемся к этой переменной откуда-то в куче (в мусорке), а если еще какую-то функцию вызовем по дороге вдруг неожиданно, то ничего не останется от той переменной в мусорке, но будем все равно к ней обращаться т.к. так учат нас. Еще добавлю - где-то даже кажется есть строгое указание в рекомендациях, что так делать категорически не рекомендуется. Вот только не помню где это и кто бы подсказал бы тут. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Des333 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Да я Вам сразу отвечу как бы все это было бы. Что тут размышлять как и чего. Это Ваш выбор :) Вы просили помощи, я пытался Вам помочь :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Это Ваш выбор :) Вы просили помощи, я пытался Вам помочь :) Ну да - спасибо и на этом. Кстати тут вообще-то ничего не выделяется - в смысле это не какая-то ненужная обертка для функции mallocc как Вы пишите с самого начала, а я пытаюсь Вам отвечать согласно такой теории и в итоге не прав оказываюсь. Здесь просто: 1. создается локальная переменная; 2. что-то делается; 3. и возвращается потом указатель на эту локальную переменную. Вот так правильное описание, что тут происходит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gosha-z 2 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Я правильно понимаю, что newconn во втором сообщении обретает значение при вызове sys_arch_mbox_fetch? Если да - то что говорит дока на эту функцию по поводу способа выделения памяти для этой структуры и последующего ее освобождения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба Я правильно понимаю, что newconn во втором сообщении обретает значение при вызове sys_arch_mbox_fetch?... Эта структура newconn вот такая - см. ее объявление ниже и на выходе из функции в ней должны появится готовые уже заполненные поля. А в вызвавшей, основной функции мы уже пользуемся этим "готовым" набором (см. коммент в 1-м куске кода: "Process the new connection."): /** A netconn descriptor */ struct netconn { /** type of the netconn (TCP, UDP or RAW) */ enum netconn_type type; /** current state of the netconn */ enum netconn_state state; /** the lwIP internal protocol control block */ union { struct ip_pcb *ip; struct tcp_pcb *tcp; struct udp_pcb *udp; struct raw_pcb *raw; } pcb; /** the last error this netconn had */ err_t last_err; /** sem that is used to synchroneously execute functions in the core context */ sys_sem_t op_completed; /** mbox where received packets are stored until they are fetched by the netconn application thread (can grow quite big) Это QueueHandle_t. */ sys_mbox_t recvmbox; #if LWIP_TCP /** mbox where new connections are stored until processed by the application thread Это QueueHandle_t. */ sys_mbox_t acceptmbox; #endif /* LWIP_TCP */ /** only used for socket layer */ #if LWIP_SOCKET int socket; #endif /* LWIP_SOCKET */ #if LWIP_SO_SNDTIMEO /** timeout to wait for sending data (which means enqueueing data for sending in internal buffers) */ s32_t send_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening netconns) */ int recv_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF /** maximum amount of bytes queued in recvmbox not used for TCP: adjust TCP_WND instead! */ int recv_bufsize; /** number of bytes currently in recvmbox to be received, tested against recv_bufsize to limit bytes on recvmbox for UDP and RAW, used for FIONREAD */ s16_t recv_avail; #endif /* LWIP_SO_RCVBUF */ /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ u8_t flags; #if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores how much is already sent. */ size_t write_offset; /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores the message. Also used during connect and close. */ struct api_msg_msg *current_msg; #endif /* LWIP_TCP */ /** A callback function that is informed about events for this netconn */ netconn_callback callback; }; ...Если да - то что говорит дока на эту функцию по поводу способа выделения памяти для этой структуры и последующего ее освобождения? Не знаю. Я новичок тут и поэтому спросил как оно работает и почему так сделано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 8 апреля, 2016 Опубликовано 8 апреля, 2016 · Жалоба 3. и возвращается потом указатель на эту локальную переменную.Где? Я вижу, что в процессе "2. что-то делается" в эту локальную переменную заносится указатель на созданный в куче объект. Потом этот указатель записывается в то место, которое было указано входным параметром. Что до вас и пытался донести des333. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться