Оптимизация размера кода C без полиморфизма - PullRequest
0 голосов
/ 29 января 2019

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

h файл:

typedef struct {
  double *array;
  size_t used;
  size_t size;
} dArray;
void init_dArray(dArray *a, size_t initialSize);
void insert_dArray(dArray *a, double element); 

typedef struct {
  char** array;
  size_t used;
  size_t size;
} sArray;
void init_sArray(sArray *a, size_t initialSize);
void insert_sArray(sArray *a, char* element); 

typedef struct {
  int* array;
  size_t used;
  size_t size;
} iArray;
void init_iArray(iArray *a, size_t initialSize);
void insert_iArray(iArray *a, int element); 

void free_dArray(dArray *a);
void free_sArray(sArray *a);
void free_iArray(iArray *a);

c файл:

void init_dArray(dArray *a, size_t initialSize) {
  a->array = (double *)malloc(initialSize * sizeof(double));
  a->used = 0;
  a->size = initialSize;
}

void init_sArray(sArray *a, size_t initialSize) {
  a->array = (char**)malloc(initialSize * sizeof(char*));
  a->used = 0;
  a->size = initialSize;
}

void init_iArray(iArray *a, size_t initialSize) {
  a->array = (int *)malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insert_dArray(dArray *a, double element) {
  if (a->used == a->size) {
    a->size = (a->size*3)/2+8;
    a->array = (double *)realloc(a->array, a->size * sizeof(double));
  }
  a->array[a->used++] = element;
}

void insert_sArray(sArray *a, char* element) {
  if (a->used == a->size) {
    a->size = (a->size*3)/2+8;
    a->array = (char**)realloc(a->array, a->size * sizeof(char*));
  }
  a->array[a->used++] = element;
}

void insert_iArray(iArray *a, int element) {
  if (a->used == a->size) {
    a->size = (a->size*3)/2+8;
    a->array = (int*)realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void free_dArray(dArray *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

void free_sArray(sArray *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

void free_iArray(iArray *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

main:

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
        iArray a;
        init_iArray(&a,5);
        for(int i=0; i<10; i++)
                insert_iArray(&a, i+1);
        for(int i=0; i<10; i++)
                printf("%d\n", a.array[i]);
        free_iArray(&a);
        exit(0);
}

Есть ли способуменьшить размер кода, с полиморфизмом или без него?

1 Ответ

0 голосов
/ 29 января 2019

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

Предоставление массива для простых элементов данных

Вы просто добавляете размер элементов в качестве параметра к вашему массиву struct:

typedef struct {
  char *array;
  size_t elementSize;
  size_t used;
  size_t size;
} Array;

void Array_init(Array *a, size_t elementSize, size_t initialSize);
void Array_insert(Array *a, const void* element);
const void* Array_at(Array *a, size_t index);
void Array_destruct(Array *a);

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

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

Предоставление массива для сложных элементов данных

Если вашим объектам нужно делать пользовательские вещи при их копировании, вам необходимопредоставить пользователю средство для предоставления необходимого поведения.Это делается с помощью указателей на функции:

typedef void (*Array_callback_copy_construct)(void* this, const void* original);
typedef void (*Array_callback_destruct)(void* this);
typedef struct {
  char *array;
  size_t elementSize;
  size_t used;
  size_t size;
  Array_callback_copy_construct copy_construct;
  Array_callback_destruct destruct;
} Array;

void Array_init(Array *a, size_t elementSize, size_t initialSize, Array_callback_copy_construct copy_construct, Array_callback_destruct destruct);
void Array_insert(Array *a, const void* element);
const void* Array_at(Array *a, size_t index);
void Array_destruct(Array *a);

Методы Array_insert() и Array_destruct() теперь просто используют предоставленные пользователем функции обратного вызова для копирования и уничтожения элементов массива.

Подробнеерасширенные версии могут также использовать обратный вызов конструктора перемещения и / или обратный вызов (перемещение) назначения.Копирование + уничтожение - это минимальный набор, который вам нужен, более высокая производительность может быть достигнута с помощью более сложных обратных вызовов.


Первый метод достаточно прост, чтобы его можно было использовать в самых разных приложениях, и я хотел быне стесняйтесь использовать его.Тем не менее, уловка использования memcpy() должна быть четко задокументирована .

Второй метод работает там, где первый метод дает сбой, но обычно он намного сложнее, чем стоит.Избегайте этого, если только вы не поймете, что это действительно единственное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...