Возврат большой переменной против ее установки с использованием указателя в аргументах - PullRequest
1 голос
/ 22 июня 2019

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

// Returning the instance

Image new_Image(const int height, const int width, const int depth) {
   Image out;
   out.width = width;
   out.height = height;
   out.depth = depth;
   out.pixels = (float*) calloc((height*width*depth), sizeof(float));
   return out;
}

Image image = new_Image(100,100,3);

// OR return a new pointer.

Image *new_Image(const int height, const int width, const int depth) {
   Image out;
   out.width = width;
   out.height = height;
   out.depth = depth;
   out.pixels = (float*) calloc((height*width*depth), sizeof(float));
   return &out;
}

Image *image;
image = new_Image(100,100,3);

// OR init outside function and populate in function. For cleanliness though I'd like as much of the image generating part to be done in the function. 

Image *new_Image(Image *out, const int height, const int width, const int depth) {
   out.width = width;
   out.height = height;
   out.depth = depth;
   out.pixels = (float*) calloc((height*width*depth), sizeof(float));
}

Image *image = (Image*) malloc(sizeof(Image));
new_Image(image, 100,100,3);

1 Ответ

1 голос
/ 22 июня 2019
  1. Image new_Image(const int height, const int width, const int depth)

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

Image *new_Image(const int height, const int width, const int depth) { Image out; - неопределенное поведение при возврате указателя на локальную переменную, которая перестает существовать при выходе из функции.

Image *new_Image(Image *out, const int height, const int width, const int depth) безопасно, если выиспользовать объекты, определенные или выделенные вне функции.Кстати, вы забыли вернуть указатель.

Опция, которую вы не упомянули в своем вопросе:

    Image *new_Image(const int height, const int width, const int depth) {
       Image *out = malloc(sizeof(*out));
       /* malloc result tests */
       out -> width = width;
       out -> height = height;
       out -> depth = depth;
       out -> pixels = calloc((height*width*depth), sizeof(float));
       /* calloc result tests */
       return out;
    }

Вы не проверяете свойрезультаты распределения памяти.Это должно быть сделано.

Эта функция также неверна:

Image *new_Image(Image *out, const int height, const int width, const int depth) {
   out.width = width;
   out.height = height;
   out.depth = depth;
   out.pixels = (float*) calloc((height*width*depth), sizeof(float));
}

Это должно быть:

Image *new_Image(Image *out, const int height, const int width, const int depth) {
   out -> width = width;
   out -> height = height;
   out -> depth = depth;
   out -> pixels = calloc((height*width*depth), sizeof(float));
   return out;
}

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

Если вы компилируете свой код с помощью компилятора C ++, используйте параметры командной строки, которые сообщат компилятору, что код является C (например, параметр gcc или g ++ -xc)

...