ПрограммированиеC разработчик

Что происходит при передаче структуры в функцию по значению и как это влияет на производительность и семантику программы?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В языке C при передаче структуры в функцию по значению создается полная копия структуры во временной области памяти (обычно на стеке функции). Это означает, что любые изменения внутри функции никак не затронут оригинальный экземпляр структуры вне функции.

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

#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // Изменит только локальную копию } void modify_by_pointer(struct Data *d) { d->flag = 20; // Изменит оригинал } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }

Преимущества передачи по указателю:

  • Нет затрат на копирование большого объема данных
  • Можно изменять исходную структуру

Недостатки передачи по значению:

  • Временные и пространственные издержки на копирование
  • Повышенное потребление стека (особенно на микроконтроллерах)

Вопрос с подвохом

Что будет, если функция возвращает структуру по значению? Какие есть риски?

Ответ:

В C можно возвращать структуру по значению из функции, например:

struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // возвращается копия }

Главный риск — производительность: создается и возвращается копия структуры. К тому же, при ошибочном возврате адреса локальной переменной структура может указывать на недопустимую память:

struct Point* bad() { struct Point p = {1, 2}; return &p; // ошибка: возврат адреса локальной переменной }

Примеры реальных ошибок из-за незнания тонкостей темы


История

На встраиваемых устройствах с малым стэком разработчик передавал большую структуру (1 КБ) по значению, вызвав стек-оверфлоу и спорадические сбои системы. Расследование показало, что копирование каждой структуры приводило к нехватке памяти стека при глубокой вложенности вызова.


История

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


История

В Open Source-проекте производительность резко просела после перехода на функцию, возвращающую по значению сложную структуру с внутренними массивами. Профилировщик выявил затраты времени процессора на ненужное многократное копирование структур.