C中的动态类型转换

时间:2018-08-02 15:54:35

标签: c casting

我正在尝试编写一个以缓冲区(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;
}   

我的问题很简单:如何“动态”投射缓冲区?如果需要,我可以添加更多的功能参数。也许可以使用宏来完成某些操作,但我无法弄清楚。

3 个答案:

答案 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);
}