C/C++
Передача параметров в функцию по адресу.
Понятно, что крупные объекты, например массивы - лучше передавать по адресу, а не по значению. Однако не всегда по адресу передают крупные объекты. Меня интересует вот этот второй случай. Почему может быть более эффективной передача по адресу?
Крупные структуры передаются по значению в следующих случаях:
В противовес популярному заблуждению о создании на стеке гигантских массивов и структур с полями, скажу, так делается далеко не всегда и не везде.
В компиляторах 1980-90-х гг присутствовали оптимизации для передаваемых по значению структур. Например, могло выделяться место в сегменте данных, или код копирования структуры вообще не генерировался, если компилятор мог надёжно определить, что вызываемая функция в неё не пишет и никуда не передаёт её адрес. Такие штуки особенно хорошо работали в сочетании с инлайном.
А маленькие структуры могли и сейчас могут передаваться целиком в регистрах, например, в x87 до 8 вещественных чисел - через регистры FPU, а в Risc архитектурах вообще навалом именованных регистров. Собственно, их и в линейке x86, начиная с Pentium Pro, было уже штук 40, а в современных моделях - по полторы-две сотни, но они недоступны по именам, и потому параметры в них передать не получится. Некоторые трюкачи с конца 1990-х задействовали для передачи массивов и структур 128-битные регистры XMM (для Pentium MMX, Pentium II, ...), это позволяло передать до килобайта данных.
В наши дни, когда все прикладные разработчики, заботящиеся о производительности, знают, что большую структуру надо передавать по ссылке, разработчики компиляторов вряд ли уделают внимание таким оптимизациям (а прошедшим онлайн-курсы чайникам они и подавно не нужны). В лучшем случае будут вызваны malloc() и memcpy(), чтобы не загаживать стек.
В общем, единственный способ надёжно определить, что происходит при передаче структуры по значению, - это смотреть ассемблерный листинг. А единственный способ получить достоверные данные о производительности - это профилирование.
- Некомпетентность программиста (учившегося на Паскале и т.п. горе-языках). Самая частая причина.
- Если параметр только входной, и в любом случае нужна отдельная копия структуры. Меньше кода писать вручную. Правда, этот подход не работает, если копия нужна после возврата из функции.
В противовес популярному заблуждению о создании на стеке гигантских массивов и структур с полями, скажу, так делается далеко не всегда и не везде.
В компиляторах 1980-90-х гг присутствовали оптимизации для передаваемых по значению структур. Например, могло выделяться место в сегменте данных, или код копирования структуры вообще не генерировался, если компилятор мог надёжно определить, что вызываемая функция в неё не пишет и никуда не передаёт её адрес. Такие штуки особенно хорошо работали в сочетании с инлайном.
А маленькие структуры могли и сейчас могут передаваться целиком в регистрах, например, в x87 до 8 вещественных чисел - через регистры FPU, а в Risc архитектурах вообще навалом именованных регистров. Собственно, их и в линейке x86, начиная с Pentium Pro, было уже штук 40, а в современных моделях - по полторы-две сотни, но они недоступны по именам, и потому параметры в них передать не получится. Некоторые трюкачи с конца 1990-х задействовали для передачи массивов и структур 128-битные регистры XMM (для Pentium MMX, Pentium II, ...), это позволяло передать до килобайта данных.
В наши дни, когда все прикладные разработчики, заботящиеся о производительности, знают, что большую структуру надо передавать по ссылке, разработчики компиляторов вряд ли уделают внимание таким оптимизациям (а прошедшим онлайн-курсы чайникам они и подавно не нужны). В лучшем случае будут вызваны malloc() и memcpy(), чтобы не загаживать стек.
В общем, единственный способ надёжно определить, что происходит при передаче структуры по значению, - это смотреть ассемблерный листинг. А единственный способ получить достоверные данные о производительности - это профилирование.
Таиржан Тохтиев
Я о другом спрашиваю: почему когда мы передаём небольшие объёмы данных, может быть эффективнее передавать входные параметры - по адресу?
Ну тут все очевидно. Упорядоченная память в виде стека будет работать многократно быстрее так как ей не нужно итерироваться через список адресов чтобы получить нужный. Можно обратиться к элементам по индексу и под капотом этого обращения будет сразу же изъятие данных. Передача по значению это копирование объекта и это минус как по времени так и по ресурсам. Ведь при передача адреса - передается только ссылка без создания объекта. Вот и получается что легковестные структуры переданные по зн могут оказаться в 10 раз быстрее, но стоит добавить в нее доп параметиы и методы и этот выигрыш будет сокращаться. Плата за такой выигрыш будет в вечном контроое за параметрами. Из за мелочной оптимизации. Лучше передавать все по ссылке и не думать о том что там у тебя...
Таиржан Тохтиев
От меня трубуют обосновать почему передача отдельных переменных по адресу иногда более выгодна, чем передача отдельных переменных по значению.
То есть когда речь о небольших объёмах данных.
То есть когда речь о небольших объёмах данных.
Похожие вопросы
- Передача параметров функцию.
- Почему при работе с небольшими объёмами данных передача параметров по адресу может быть эффективнее, чем по значению?
- Передача строк в функцию С++
- Передача в метод класса указателя на функцию C++
- Как отсортировать массив в зависимости от третьего параметра функции?
- Не понимаю как в параметрах функции учесть, например, только положительные числа, когда флоат и т. д. Тема перегрузка функций
- Не могу разобраться. Функция удаления отрицательных элементов вектора
- Как в функции распечатать двумерный динамический массив в Си
- Как завершить условие в функции?
- Возвращение функции return func(); (Си)