Динамическая переменная типа с пустым указателем (в конечном итоге динамическое приведение типов) в C
Я только что пришел к вопросу с динамическим типом переменной (не совсем динамическим, но должен определяться во время выполнения), ситуация такова:
У меня есть функция, которая принимает двойной массив, преобразует его в целое число и записывает в файл, целое число может иметь разную длину битов, например 8, 16 и 32. Поскольку это массив, я хочу использовать указатель для доступа к финалу результат (массив). Поэтому сейчас я использую указатель void с помощью malloc и case case, но необходимо будет добавлять регистр switch каждый раз, когда я пытаюсь получить доступ или изменить этот массив, мой вопрос: есть ли лучший способ сделать это?
текущий код выглядит так:
void foo(double * arr, int len, int iBits, FILE *fh)
{
void * newArr;
int iBytePerElement, iBase,i;
iBytePerElement = iBits / 8;
iBase = (1 << (iBits - 1)) - 1;
switch (iBytePerElement)
{
case 1:
{
newArr = (int8_t *) malloc(sizeof(int8_t)*len);
break;
}
case 2:
{
newArr = (int16_t *) malloc(sizeof(int16_t)*len);
break;
}
case 4:
{
newArr = (int32_t *) malloc(sizeof(int32_t)*len);
break;
}
}
for (i = 0; i < len; ++i)
{
switch (iBitPerElement)
{
case 1:
{
((int8_t *)newArr)[i] = (int8_t)(arr[i]*iBase);
break;
}
case 2:
{
((int16_t *)newArr)[i] = (int16_t)(arr[i]*iBase);
break;
}
case 4:
{
((int32_t *)newArr)[i] = (int32_t)(arr[i]*iBase);
break;
}
}
}
fwrite(newArr, iBytePerElement, iBytePerElement*len,fh);
}
1 ответ
Делая несколько предположений о том, что вы, вероятно, имели в виду, где ваш пример кода не определен (прокомментирован), вот как я могу это сделать:
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
void *foo(double * arr, int len, int iBits) //should return the malloced array not void
{
void * newArr;
int iBytePerElement, iBase, i;
iBytePerElement = iBits / 8;
iBase = (1 << (iBits - 1)) - 1;
if(NULL==(newArr = malloc(iBits/CHAR_BIT))) return NULL; //replace the first switch
//which obviously meant to alloc sizeof(int16_t)*len in the case 2 branch (not (sizeof(int8_t)*len) etc
for (i = 0; i < len; ++i) {
switch(iBytePerElement){
break; case 1: ((int8_t *)newArr)[i] = arr[i]*iBase;
break; case 2: ((int16_t *)newArr)[i] = arr[i]*iBase;
break; case 4: ((int32_t *)newArr)[i] = arr[i]*iBase;
}
}
return newArr;
}
По сути, вам нужен только второй переключатель.
Если вы хотите избавиться от 2-го переключателя, вы можете заменить его на функцию воспроизведения указателя. Например:
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#define MK_FN(Bits) \
void to##Bits(void *newArr, double const*arr, int len) \
{ \
int i; for(i=0; i < len; i++) ((int##Bits##_t *)newArr)[i] = arr[i]*((1<<(Bits-1)-1)); \
}
MK_FN(8)
MK_FN(16)
MK_FN(32)
void *foo(double * arr, int len, int iBits) //should return the malloced array not void
{
void * newArr;
int iBytePerElement = iBits / 8;
if(NULL==(newArr = malloc(iBits/CHAR_BIT))) return NULL;
((void (*[])(void *,double const*, int)){ [1]=to8, [2]=to16, [4]=to32, })[iBits](newArr,arr,len);
return newArr;
}