簡體   English   中英

C中的動態類型轉換

[英]Dynamic type casting in C

我正在嘗試編寫一個以緩沖區(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;
}   

我的問題很簡單:如何動態地釋放緩沖區? 如果需要,我可以添加更多的功能參數。 也許可以使用宏來完成某些工作,但我無法弄清楚。

請改用宏:

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) (*)是為了避免有符號/無符號比較問題。 如果使用例如INCREMENT (buffer + 4, 12)調用宏,則在buffer周圍加括號可以防止出現問題。

在調用方,它看起來像這樣:

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給出了一種解決方法,有關詳細信息,請參見此處

如果要處理的特定類型數量有限,則可以為每種類型編寫一個單獨的函數。 如果您不想為每種類型選擇正確的功能,則可以使用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;
}

您只能擁有像這樣的愚蠢的東西(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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM