我正在尝试编写一个以缓冲区(void *),类型大小,类型名称和元素数量为参数的函数。缓冲区可能包含有限数量的基本类型(int,float,double,...)的值。在这个函数中,我希望能够增加每个值。看起来像这样:
void increment (void *buffer, int type_size, char *type_name, int n_elements)
{
for (int i=0; i<n_elements; i++)
((MACRO(type_name))(buffer))[i]++; // ???
return;
}
我的问题很简单:如何“动态”投射缓冲区?如果需要,我可以添加更多的功能参数。也许可以使用宏来完成某些操作,但我无法弄清楚。
答案 0 :(得分:0)
改为使用宏:
INCREMENT (buffer, n_elements) \
{\
for (typeof(n_elements) i=0; i < n_elements; i++)\
(buffer)[i]++;\
}
或更好(也适用于浮点类型):
INCREMENT (buffer, n_elements) \
{\
for (typeof(n_elements) i=0; i < n_elements; i++)\
(buffer)[i] += 1;\
}
typeof(n_elements)
(*)是为了避免有符号/无符号比较问题。
如果您使用buffer
调用宏,则INCREMENT (buffer + 4, 12)
周围的括号可以防止出现问题。
在主叫方看起来像这样:
double buffer[100];
//[...] Initialize here your buffer
INCREMENT (buffer, 100); //Semicolon is optional, but I prefer having it
或
#define BUFFER_SIZE 200
unsigned int* p = malloc(sizeof(*p) * BUFFER_SIZE);
//[...] Initialize here your buffer
INCREMENT (p, BUFFER_SIZE); //Semicolon is optional, but I prefer having it
typeof
实际上是非标准的,C11中的_Generic
给出了一种解决方法,详细信息here可用。
答案 1 :(得分:0)
如果要处理的特定类型数量有限,则可以为每种类型编写单独的函数。如果不想为每种类型选择正确的功能,则可以使用C11的_Generic
根据类型进行选择。作为一个基本示例:
#include <stdio.h>
#include <stdlib.h>
void increment_int(int *, int);
void increment_long_long_int(long long int *, int);
#define increment(buffer, n_elements) _Generic((buffer), \
int *: increment_int, \
long long int *: increment_long_long_int \
)(buffer, n_elements)
void increment_long_long_int (long long int *buffer, int n_elements)
{
for (int i=0; i<n_elements; i++)
{
buffer[i]++;
}
return;
}
void increment_int (int *buffer, int n_elements)
{
for (int i=0; i<n_elements; i++)
{
buffer[i]++;
}
return;
}
int main(void) {
int buff[20] = {0};
long long int buff2[20] = {0};
increment(buff, 20);
increment(buff2, 20);
printf("%d\n", buff[5]);
printf("%lld\n", buff2[8]);
return EXIT_SUCCESS;
}
答案 2 :(得分:-2)
您只能有这样的愚蠢的东西(gcc版本):
#include <stdint.h>
void incrementAlmostAnySize(void *ptr, size_t size, size_t element, int sign)
{
union
{
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
int8_t i8;
int16_t i16;
int32_t i32;
int64_t i64;
}*uptr = ptr + size * element; //non gcc : (void *)((uint8_t *)ptr + size * element);
if(sign)
{
switch(size)
{
case 1:
uptr -> i8++;
break;
case 2:
uptr -> i16++;
break;
case 4:
uptr -> i32++;
break;
case 8:
uptr -> i64++;
break;
default:
break;
}
}
else
{
switch(size)
{
case 1:
uptr -> u8++;
break;
case 2:
uptr -> u16++;
break;
case 4:
uptr -> u32++;
break;
case 8:
uptr -> u64++;
break;
default:
break;
}
}
}
用法:
char x[1000];
void foo()
{
incrementAlmostAnySize(x, sizeof(long long), 10, 1);
incrementAlmostAnySize(x, sizeof(uint32_t), 2, 0);
for(size_t i = 0; i < sizeof(x) / sizeof(uint64_t); i ++)
incrementAlmostAnySize(x, sizeof(uint64_t), i, 0);
}