2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4, 5  След.
 
 Re: Возврат структуры из функции
Сообщение21.07.2023, 23:14 
Аватара пользователя


27/07/16
556
TheRuinedMap в сообщении #1601957 писал(а):
Это "бурная дискуссия"?

это ирония)) но удивление и там у иных было. По аналогии с массивами . Передать по значению структуру, ладно если маленькую, в которую могут добавиться потом ещё поля (бог весть каких размеров), чтобы потом эту же структуру вернуть столь экзотичным способом? Передать адрес проще и прозрачнее. И эффективнее. Судя по всему, и у иных компиляторов возникали непонятки)). Короче, вредная идея)). Хотя и стандартная. По любому это вносит путаницу. Конечно, можно потом соорудить хитрый вызов функции прямо на вход другой функции, в параметре такого же типа, но тогда
верните не структуру, а указатель на структуру и получите тоже самое, но понятнее. Получается, что передача по значению становится не тем, чем кажется, а скрытой передачей по ссылке. То есть параметр, передается по значению, но изменяется внутри функции? Ясности это не вносит. Нет, такой хоккей нам не нужен. Пардон))) Переменная внутри функции не описана как статическая, отсюда возникает ощущение: это как? Сколько обычно такая переменная живёт? Она не указует ни на кого. Тип не указательный, значит … ересь, либо это ссылка, которая как ссылка не описана, если не считать, что её тип сияет в описании возвращаемого функцией типа! Это должен тонко обходить компилятор,, заметив, что эта переменная послана лесом, пардон, на выход , значит память для неё не надо выделять на стеке, но как для адреса идущего свыше, что, как мы видели, не у каждого компилятора выходит.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение21.07.2023, 23:54 
Заслуженный участник
Аватара пользователя


01/09/13
4320
Genaa в сообщении #1601969 писал(а):
По аналогии с массивами

Нет такой аналогии.
Genaa в сообщении #1601969 писал(а):
Получается, что передача по значению становится не тем, чем кажется, а скрытой передачей по ссылке.

Нет. Нет никакой скрытой передачи.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 00:15 
Заслуженный участник


31/12/05
1480
Genaa в сообщении #1601969 писал(а):
Передать по значению структуру, ладно если маленькую, в которую могут добавиться потом ещё поля (бог весть каких размеров)
Да-да, в вектор из двух элементов потом добавится счетчик ссылок, дата и время создания и случайная соль, чтобы не хакнули.
Genaa в сообщении #1601969 писал(а):
, чтобы потом эту же структуру вернуть столь экзотичным способом? Передать адрес проще и прозрачнее. И эффективнее. Судя по всему, и у иных компиляторов возникали непонятки)).
Даже TinyC, у которого в принципе отсутствует флаг оптимизации, принимает два входных вектора в rcx и rdx, а результат возвращает в rax, и при возврате по указателю (переданному в r8) получается на три команды больше.

У gcc тоже входные структуры лежат в rdi и rsi, выход в rax, в варианте с возвратом по указателю этот указатель передается на вход в rdx. Без оптимизации возврат по значению также короче. С -O1 и -O2 для возврата по значению требуется больше команд, но они короче и не обращаются к памяти. Что забавно, с ключом -O3 получается почти одинаковый код с использованием MMX, просто в одном варианте результат пишется в rax, в другом в [rdx].
Genaa в сообщении #1601969 писал(а):
Короче, вредная идея)). Хотя и стандартная. По любому это вносит путаницу.
Если структура влезает в машинное слово (или даже в два), передача по значению выгоднее, а часто и понятнее. Сравните dot(add(a, b), add(c, d)) и код с указателями:
Код:
struct vect t1, t2;
add(&a, &b, &t1);
add(&c, &d, &t2);
return dot(&t1, &t2);
(Это мы еще вспомнили, что входные параметры тоже надо передавать по указателю, а то чё они, вдруг там еще поля добавятся)
Genaa в сообщении #1601969 писал(а):
Это должен тонко обходить компилятор,, заметив, что эта переменная послана лесом, пардон, на выход , значит память для неё не надо выделять на стеке, но как для адреса идущего свыше, что, как мы видели, не у каждого компилятора выходит.
Я еще понимаю, что компиляторы могут не осиливать что-то из C++20. Но если автор до 2017 года не справлялся со стандартом C89, то компилятор этот явно игрушечный.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 00:51 
Аватара пользователя


27/07/16
556
[quote="Geen в сообщении #1601976"]Нет никакой скрытой передачи[/q

Вы можете записать в массив или даже простую переменную (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции, после точки её вызова, просто вернув этот адрес? Разве это не похоже? Не статические переменные, описанные внутри функции, и не ссылочного типа, которым не выделена память явным образом, живут после завершения вызова функции? Это где. Но зачем так?
Структура передаётся по значению. Это о чём говорит? Но изменяется внутри. Зачем это маскировать?
Если вы её поля изменять собрались. Передать адрес не проще ли? А такой способ, хоть и стандартно, но это маскирует..Речь не о технических возможностях, а о восприятии текста. Многое чего можно куда поместить, дело в том, чтобы это не сбивало с толку читателя текста, который может быть будет что-то изменять или добавлять.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 01:12 
Заслуженный участник


31/12/05
1480
Код:
int sum_int(int int1, int int2)
{
   int otvet;
   otvet = int1 + int2;

   return otvet;
}
Вы можете записать в простую переменную otvet (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции, после точки её вызова, просто вернув этот адрес? Разве это не похоже? Не статические переменные, описанные внутри функции, и не ссылочного типа, которым не выделена память явным образом, живут после завершения вызова функции? Это где. Но зачем так?

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 01:35 
Аватара пользователя


27/07/16
556
tolstopuz в сообщении #1601994 писал(а):
Но зачем так?

Вы не имеете этой переменной снаружи. Дело вот в чём— у Кого-то описана структура некая где-то наружи. Вы знаете, что её поля нужно передать потом, после конца света, или накануне. Он видит параметр, который передается по значению. Знач его деньги (поля) внутри функции не изменятся в функции. Просто вам скажут, мол, там Нечто прочитает и учтет ваши доходы. Для отчёта. Вы не заметите, что оно там, возвращаясь, изменяет вашу структуру, вписав в поля свои представления о прекрасном. Может быть такое? Почему нет? А если вы знаете, что передаёте адрес, значит сохраните свои данные в заначке. И потом восстановите, если надо. Вот о чем речь. От того что я передал значение локальной переменной наружу… этой переменной ни холодно, ни жарко. Её уже нет. У неё судьба такой. Но совать сейф в черный ящик, который говорит, мол, гарантирую сохранность, а потом опустошает его — не есть хорошо))
Таки так и где-то даже вот))))

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 01:37 


18/09/21
1683
Наверно есть причина, почему в API передают структуры по ссылке, а не по значению.
Berkeley sockets:
Используется синтаксис C
struct sockaddr_in sa;
if (bind(SocketFD,(struct sockaddr *)&sa, sizeof sa) == -1) {}

POSIX:
Используется синтаксис C
struct timespec curTime;
clock_gettime(CLOCK_REALTIME, &curTime);

WinAPI:
Используется синтаксис C
typedef struct tagWNDCLASSA {...} WNDCLASSA, *PWNDCLASSA, *NPWNDCLASSA, *LPWNDCLASSA;
LPWNDCLASSA lpWndClass;
if (GetClassInfoA(hInstance, lpClassName, lpWndClass)) {}

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 02:20 
Заслуженный участник


31/12/05
1480
Genaa в сообщении #1601995 писал(а):
Вы не заметите, что оно там, возвращаясь, изменяет вашу структуру, вписав в поля свои представления о прекрасном. Может быть такое? Почему нет?
Я не понимаю, какое отношение этот поток сознания имеет к обсуждаемой функции sum_vect. Никаких чужих структур она не меняет. Куда девать результат ее выполнения, определяет тот, кто ее вызвал. Может, присвоит куда-нибудь, может, сразу передаст как параметр в другую функцию, а может, сам сделает return sum_vect(...).
Genaa в сообщении #1601992 писал(а):
Вы можете записать в массив или даже простую переменную (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции
Ошибка этих рассуждений в том, что у переменной вообще не обязан быть адрес. Можно, например, написать register struct vect otvet, и тогда операция взятия адреса у otvet просто будет запрещена.

Повторюсь, я не вижу принципиальной разницы между возвратом struct vect и int. Все ваши рассуждения про struct vect применимы к int, кроме одной мелочи, что struct vect можно менять и по частям (и целиком тоже), а int только целиком.

-- Сб июл 22, 2023 02:45:40 --

zykov в сообщении #1601996 писал(а):
Наверно есть причина, почему в API передают структуры по ссылке, а не по значению.
Причин много и они разные.
У sockaddr фактически сделано наследование, то есть реально по этому указателю лежит другая структура, например, sockaddr_in. Такое по значению не передается.
timespec - у меня есть разные предположения. Например, чтобы не включать <time.h> в <threads.h>. Хотя, наверное, она появилась раньше, чем потоки. Но если она древняя, то при ее проектировании стоило бы подумать о том, что передавать 64-битную структуру по значению в 16-битных архитектурах неэффективно.
WNDCLASSA - большая и сложная структура, которая к тому же владеет ресурсами, например, кистью, поэтому копировать ее, не задумываясь о владении, некорректно.

-- Сб июл 22, 2023 02:58:36 --

А возврат структур по значению в сишных API практически не используется, потому что возвращаемое значение часто используется как код возврата.

-- Сб июл 22, 2023 03:01:13 --

Вот структура POINT в WinAPI маленькая и передается по значению:
Используется синтаксис C
BOOL PtInRect(
  [in] const RECT *lprc,
  [in] POINT      pt
);
А RECT - большая.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 03:20 
Аватара пользователя


28/10/21
99
zykov в сообщении #1601996 писал(а):
Наверно есть причина, почему в API передают структуры по ссылке, а не по значению.


Причины заключаются в том, что

1. Когда-то во времена динозавров в зачаточном С действительно нельзя было копировать структуры, в т.ч. передавать и возвращать их по значению. Однако такая возможность появилась уже тогда давно, еще до K&R С. См Recent Changes to C

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

-- 21.07.2023, 16:24 --

tolstopuz в сообщении #1601994 писал(а):
Код:
int sum_int(int int1, int int2)
{
   int otvet;
   otvet = int1 + int2;

   return otvet;
}
Вы можете записать в простую переменную otvet (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции, после точки её вызова, просто вернув этот адрес?


Можете. Но так не делают. Возврат по значению не реализуют через возврат указателя на "мертвую" переменную. Возврат по значению реализуется либо как возврат через регистр (или набор регистров), либо как синтаксический сахар над записью данных в предоставленный вызывающим кодом буфер.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 05:47 
Аватара пользователя


27/07/16
556
tolstopuz в сообщении #1602001 писал(а):
Ошибка этих рассуждений в том, что у переменной вообще не обязан быть адрес. Можно, например, написать register struct vect otvet, и тогда операция взятия адреса у otvet просто будет запрещена.
Я не писал про register. Hигде и ни разу. В чём тогда ошибка? В том, что у переменной не всегда есть адрес? А разве я утверждал обратное? Свят,свят, вроде нет! Однако как вернуть адрес локальной переменной без префиксa register, хоть тушкой, хоть чучелком, дабы потом туда чего записать, кстати, куда? Хотя может есть способ? И, да, размер имеет значение, не всякую структуру можно шустро передать по значению. Особенно, если она прирастет в размерах. Что случается. Дело не в эффективности.. Согласен,что в исходном примере нет модификации внешней структуры, там otvet не из параметров, но почему бы ему не оказаться там, в варианте функции, которая инкреминтирует его поля? Если такой inc, прирастив поля копии своего параметра на единицу, вернет результат другой внешней структуре, присвоенный оной, то это по фен шую, только если поля входного параметра не изменятся.Иначе это не параметр, передаваемый по значению. Вход по значению не меняет входящего. Или это другая опера. И ничего более.

-- 22.07.2023, 06:24 --

TheRuinedMap в сообщении #1602010 писал(а):
тем не менее передача через указатель остается де-факто стандартом.
Хороший менталитет. Увы, но раньше было лучше, как поётся в одной песне одной древней группы. Впрочем, стандарты уходят и приходят, а навороченное по разным стандартам не даёт скучать потомкам)). Ясности все меньше, туманы всё гуще.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 10:50 
Заслуженный участник
Аватара пользователя


16/07/14
8469
Цюрих
TheRuinedMap в сообщении #1602010 писал(а):
Можете
Разве?
C standard писал(а):
6.2.4.2. ... If an object is referred to outside of its lifetime, the behavior is undefined.
6.2.4.4. An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration.
6.2.4.5. For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 13:34 
Экс-модератор
Аватара пользователя


23/12/05
12047
TheRuinedMap в сообщении #1602010 писал(а):
2. Даже при возможности копирования структур, в языке доминировал (и доминирует) менталитет, согласно которому, все что потенциально имеет размер больше указателя эффективнее передавать и возвращать по указателю, а не по значению. Именно по этой причине структуры обычно передают и возвращают по указателю. Утверждение о более высокой эффективности такой передачи на современных полномасштабных платформах неверны для структур небольшого размера, но тем не менее передача через указатель остается де-факто стандартом.

Не соглашусь. Работа с указателями напрямую постоянно сопряжена с вероятностью либо залезть в не те области памяти, либо, что объект, на который указывает указатель, умрет,а указатель будет показывать на мусор. Лично я стараюсь передавать на вход функции по ссылке, типа
Используется синтаксис C++
void myFunc(std::vector<int>const& arg)
{
}

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

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 14:00 
Заслуженный участник


31/12/05
1480
TheRuinedMap в сообщении #1602010 писал(а):
Можете. Но так не делают. Возврат по значению не реализуют через возврат указателя на "мертвую" переменную. Возврат по значению реализуется либо как возврат через регистр (или набор регистров), либо как синтаксический сахар над записью данных в предоставленный вызывающим кодом буфер.
Это был сарказм. Вы ответили не тому человеку, вот правильный адресат:
Genaa в сообщении #1601992 писал(а):
Вы можете записать в массив или даже простую переменную (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции, после точки её вызова, просто вернув этот адрес?
Только у меня ощущение, что он очень старательно не понимает аргументов и продолжает поток сознания.

-- Сб июл 22, 2023 14:02:42 --

Genaa в сообщении #1602023 писал(а):
В чём тогда ошибка? В том, что у переменной не всегда есть адрес? А разве я утверждал обратное?
Да, утверждали, даже С Большой Буквы:
Genaa в сообщении #1601992 писал(а):
Вы можете записать в массив или даже простую переменную (описанную внутри функции без префикса static) некое значение и прочитать записанное По Этому Адресу уже после завершения вызова функции


-- Сб июл 22, 2023 14:17:02 --

Genaa в сообщении #1602023 писал(а):
Я не писал про register. Hигде и ни разу.
А компилятор по собственной инициативе, без ключевого слова, решил разместить otvet в регистре, раз в программе от него не берется адрес. И все, у него нет адреса.
Genaa в сообщении #1602023 писал(а):
Однако как вернуть адрес локальной переменной без префиксa register, хоть тушкой, хоть чучелком, дабы потом туда чего записать, кстати, куда?
Зачем вы хотите это сделать? В обсуждаемом коде этого нет.
Genaa в сообщении #1602023 писал(а):
Если такой inc, прирастив поля копии своего параметра на единицу
Вы про такое?
Используется синтаксис C
int test(int x)
{
   int otvet;
   otvet = x * x;
   x += 1;
   return otvet;
}

int main()
{
    int x = 5;
    printf("%d\n", test(x));
    printf("%d\n", x);
}
 
Вы считаете, что после этого внешняя переменная x изменится и второй printf напечатает 6? Или вы считаете, что со struct vect эффект будет другим, чем с int?

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 15:27 


02/10/12
303
Используется синтаксис C
 |<-----------------стек-------------------->|
 |        |            |          |          |
 |адрес   |возвращаемое|аргументы |локальные |
 |возврата|значеие     |структуры |переменные|
          |структура   |
 


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

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

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

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

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

 Профиль  
                  
 
 Re: Возврат структуры из функции
Сообщение22.07.2023, 18:30 
Аватара пользователя


27/07/16
556
tolstopuz в сообщении #1602086 писал(а):
Вы считаете, что после этого внешняя переменная x изменится и второй printf напечатает 6? Или вы считаете, что со struct vect эффект будет другим, чем с int?


Речь про другое.

код: [ скачать ] [ спрятать ]
Используется синтаксис C

struct Mumu
{
    int х;
    int t;
};

struct Mumu gerasim(struct Mumu отvet)
{
   otvet.x++;
   return otvet;
}

int main()
{
    struct Mumu mu;
     mu.x = 5;  
     gerasim(mu);  /* mu.x == 5 , иначе проблема */
     mu = gerasim(mu); /* mu.x == 6 , иначе за что боролись? */

}

 


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

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 65 ]  На страницу Пред.  1, 2, 3, 4, 5  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group