Arlleex 131 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба Попробую внести ясности-понятности. // допустим, Data разместилась по адресу 0x5000 // значение по адресу 0x5000 после присвоения будет равно 10 int Data = 10; // допустим, pData разместилась по адресу 0x10000 // значение по адресу 0x10000 после присвоения будет равно 0x5000 (адрес Data) int *pData = &Data; // чтобы работать на чтение/запись с содержимым Data через pData, используем операцию разыменовывания int a = *pData; // a == 10 *pData = 20; // теперь Data == 20 // допустим, ppData разместилась по адресу 0x20000 // значение по адресу 0x20000 после присвоения будет равно 0x10000 (адрес pData) int **ppData = &pData; // чтобы работать на чтение/запись с содержимым pData через ppData, используем операцию разыменовывания int *a = *ppData; // a == 0x10000 // чтобы получить доступ к переменной Data, используется двойное разыменовывание int b = **ppData; // b == 20 У меня, например, двойной уровень косвенного обращения (указатель на указатель) используется в кольцевом буфере. Имеется автомат, который расшифровывает принимаемые символы от фреймера (байт-стаффинг) по UART и складывает их в кольцевой буфер. Когда фрейм данных полностью принят, нужно как-то сообщить пользователю о размере принятого сообщения. Поэтому, перед тем, как я складирую принимаемые символы в кольцевой буфер, я резервирую в нем один байт для записи в него размера посылки после того, как весь фрейм будет принят. Чтобы не городить лишних телодвижений, я использую что-то наподобие вот такой конструкции: char *pMessageSize; // адрес элемента в кольцевом буфере, содержащий информацию о размере принятого сообщения ... RingBufferReserveByte(&pMessageSize); // прототип RingBufferReserveByte(char **Address) ... // после приема всей посылки прямой записью в память добавил в заранее зарезервированное место в кольцевом буфере информацию о размере сообщения, не думая по положениях head- и tail-указателей буфера *pMessageSize = ByteCounter; // ну а тут уже можно выдать семафор в основную программу, где она считывает первый элемент - видит размер сообщения - считывает его, перемещает позицию следующего чтения и, (если там еще что-то уже успело придти) двигается так дальше Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба 2Метценгерштейн: Видимо я утерял нить рассуждений. :rolleyes: Почему? Соглашения по стилю обычно это определяют. Что по ссылке передаются данные которые долго копировать, но не нужно менять, а по указателям можно делать что угодно и это хорошо будет видно в коде благодаря звездочке/стрелке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 4 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба В стеке аллокируется кадр под все аргументы Простите, что делается? :05: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба Простите, что делается? :05: Выделяется (англ. allocate). Но что там куда выделяется зависит еще все-таки от соглашения вызовов используемого компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Метценгерштейн 0 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба Arlleex, спасибо за подробное изложение. Прошлись по основам. Подвели все к общему знаменателю. Могли бы в том же духе первый пост разложить? Именно оригинальный пример из кода. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 35 27 июля, 2018 Опубликовано 27 июля, 2018 · Жалоба Для АРМ параметры передаются через регистры (пока хватает). Так что Ваши параметры после выхода просто пропадут. Проще посмотреть отладчиком, если лень книги читать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 28 июля, 2018 Опубликовано 28 июля, 2018 · Жалоба Могли бы в том же духе первый пост разложить? Именно оригинальный пример из кода. Ну, попробую. // определение типа данных ble_advdata_tk_value_t typedef struct { uint8_t tk[BLE_GAP_SEC_KEY_LEN]; }ble_advdata_tk_value_t; // oob_key - указатель на любой объект в памяти, имеющий тип ble_advdata_tk_value_t ble_advdata_tk_value_t *oob_key; Допустим, для общего случая, что oob_key разместился по адресу 0x1000 и был объявлен в функции, поэтому без явной инициализации в нем будет лежать мусор. Значит по адресу 0x1000 сейчас лежит мусор. В вызове err_code = nfc_tk_value_get(oob_key); // прототип ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t *pp_tk_value) мы передаем копию значения oob_key (на данный момент мусор) в функцию nfc_tk_value_get(), а это значит, что, во-первых, в функцию передался мусор, а во-вторых, функция не сможет изменить значение по адресу 0x1000 (значение oob_key), поскольку она не знает адрес oob_key. Поэтому повышается уровень косвенного обращения вызовом err_code = nfc_tk_value_get(&oob_key); // прототип ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t **pp_tk_value) Здесь уже функции передается число 0x1000, и эта функция может что угодно делать с этим числом (это адрес oob_key) - например, инициализировать его адресом динамически созданного объекта типа ble_advdata_tk_value_t. В Вашем случае *pp_tk_value = &m_device_tk; // записать по адресу 0x1000 (то есть в ячейку oob_key) адрес объекта m_device_tk типа ble_advdata_tk_value_t Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Метценгерштейн 0 28 июля, 2018 Опубликовано 28 июля, 2018 · Жалоба Спасибо. Упустил из вида момент, что ble_advdata_tk_value_t *oob_key; это просто объявление переменной, но она непроинициализирована. А здесь err_code = nfc_tk_value_get(&oob_key); мы просто передаем адрес (0х1000) этой переменной. Как обычно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Метценгерштейн 0 29 июля, 2018 Опубликовано 29 июля, 2018 · Жалоба Спасибо. Упустил из вида момент, что ble_advdata_tk_value_t *oob_key; это просто объявление переменной, но она непроинициализирована. А здесь err_code = nfc_tk_value_get(&oob_key); мы просто передаем адрес (0х1000) этой переменной. Как обычно. а вот здесь зачем указатель на указатель? ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value) Разве не достаточно было так: ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value) { pp_tk_value = &m_device_tk; } Давайте аналогию приведем. int a; int *p; p = &a; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrew_b 14 29 июля, 2018 Опубликовано 29 июля, 2018 · Жалоба Давайте аналогию приведем. int a; int *p; p = &a; Давйте. int a; int *p; p = &a; Это "снаружи" функции. В самой функции параметр (например, p1) является копией p. Изменяя p1, вы не можете изменить p. /* При вызове функции происходит следующее */ int *p1 = p; /* в параметр копируется указатель, передаваемый в функцию */ int b; /* локальная переменная функции */ p1 = &b; /* изменяется p1, т.е копия p, но сам p не изменяется */ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GeorgK 1 31 августа, 2018 Опубликовано 31 августа, 2018 · Жалоба Возможно (вроде этого не было), стоит ещё упомянуть о передаче аргумента в функцию по адресу? void func(int &k) { k = 5}; .... int k = 0; func(k); //Здесь k равно 5. Иногда это удобнее, если только не забывать, что изменение аргумента скажется на вызывающей функции. Впрочем, для передачи сложных типов часто используется запись вроде func(const int &arg), позволяющая не тащить при вызове в стек весь тип, а обойтись его адресом. А компилятор проследит, чтобы по ходу функции аргумент не был изменён. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 1 сентября, 2018 Опубликовано 1 сентября, 2018 · Жалоба Давайте давайте учтите плохому. "Within function parameter lists all references must be const: void Foo(const string &in, string *out); In fact it is a very strong convention in Googlecode that input arguments are values or const references while output arguments are pointers." https://google.github.io/styleguide/cppguid...tput_Parameters И это абсолютно правильно, делать ф-цию, вызов которой семантически выглядит как принимающая параметр по значении, а на деле давать ей неконстантную ссылку - форменное свинство Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 1 сентября, 2018 Опубликовано 1 сентября, 2018 (изменено) · Жалоба а вот здесь зачем указатель на указатель? ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t ** pp_tk_value) Разве не достаточно было так: ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value) { pp_tk_value = &m_device_tk; } Вам надо понять (один раз и на всю жизнь), для чего в качестве аргумента функции передавать указатель на указатель. Поймёте это - поймёте и ваш код. То, что вы знаете, и о чём пишется в любом учебнике по С 1.Передавая объекты в функцию по-значению, вы сможете использовать их (значения), но не сможете их изменить. Все изменения аргументов внутри функции изменят лишь копии объектов, переданных в функцию, но не сами объекты. Т.е. изменение копии никак не отражается на оригинале, с которого копия была снята. 2. Чтобы можно было изменять значения объекта изнутри функции, в функцию в качестве аргумента надо передать не сам объект, а указатель на него. В этом случае в функцию передастся копия указателя на объект. Но т.к. копия указателя на объект указывает на тот же самый объект, что и исходный указатель, то этом случае функция через косвенную адресацию будет иметь доступ к такому объекту. Ведь в качестве параметра ей придёт указатель (т.е. фактически адрес) объекта. Зная адрес объекта (т.е. имея копию указателя на него) всегда можно изменить и сам объект, разыменовав указатель и присвоив ему новое значение. А теперь то, что из этого следует, но на чём не акцентируется внимание в учебниках или вообще не говорится. 3. А что делать, если вам надо внутри функции изменить значение объекта имеющего тип указателя? Т.е. надо внутри функции присвоить указателю адрес другого объекта. Как такое сделать? Если передать в функцию сам указатель, то можно будет изменять тот объект, на который он указывает, но не сам указатель. А нам то этого не надо. Нам надо, чтобы указатель после выхода из функции указывал на другой объект (содержал его адрес). Вот для этого и приходится передавать в качестве аргументов функциям указатель на указатель. Очень простой пример для иллюстрации сказанного в п. 3 // Произвольный тип данных пользователя (предположим, int) typedef int usertype_t; // Функция, изменяющая значение указателя на объект типа usertype_t // PtrToPtrToObj -указатель на указатель на объект типа usertype_t // PtrToNewObj - указатель на новый объект void SetPtrToNewObj (usertype_t** PtrToPtrToObj, usertype_t* PtrToNewObj) { *PtrToPtrToObj=PtrToNewObj; } int main (){ // Объекты типа usertype_t usertype_t ObjA, ObjB; // Указатель на объект типа usertype_t usertype_t* ObjPtr=&ObjA; // Теперь ObjPtr указывает на объект ObjA // Меняем значение указателя. Нам нужно, чтобы он теперь указывал на другой объект // Эквивалент строки: ObjPtr=&ObjB; SetPtrToNewObj (&ObjPtr,&ObjB); // Теперь ObjPtr указывает на объект ObjB } А теперь зная это посмотрим на код: ret_code_t nfc_tk_value_get(ble_advdata_tk_value_t * pp_tk_value) { pp_tk_value = &m_device_tk; } Что он делает? pp_tk_value - это аргумент функции. Т.е. при вызове функции в него копируется значение типа ble_advdata_tk_value_t *. Т.е. это копия указателя на объект типа ble_advdata_tk_value_t. КОПИЯ указателя, а не сам указатель! pp_tk_value = &m_device_tk; - что вы сделали этой строкой? Вы присвоили КОПИИ УКАЗАТЕЛЯ новое значение. Но изменение КОПИИ никак не повлияло на оригинал. Оригинальный указатель остался прежним. А после выхода из функции pp_tk_value вышел из области видимости. Т.е. эта строка не изменила никаких объектов программы. А должна была присвоить указателю новое значение - адрес объекта m_device_tk типа ble_advdata_tk_value_t. Изменено 1 сентября, 2018 пользователем Professor Chaos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться