void指针和不同大小的内存

时间:2014-12-04 10:36:44

标签: c casting

我有一个函数将unsigned int的字符串转换为unsigned int对应函数。

我希望能够将无符号类型的ANY大小作为容器传递给它,并指定一个值的大小限制。函数原型是这样的:

str_to_uint(void *tar, const char *str, const uint64_t lim) 

uint64_t *tar是无符号整数的存储位置,*str是数字的字符串,uint64_t lim*tar能够的大小限制持。

因为sizeof(tar)是变量的,将*tar强制转换为uint64_t *然后包含转换后的变量是否安全?我知道它总是小于实际类型,因为我用lim变量检查它。

是允许的吗?

基本上它可以归结为这个

  1. 我有一个无符号类型的变量,其中sizeof(variable)是1,2,3或4。
  2. 我通过(void *)&variable将变量传递给函数。
  3. 在函数中我将其转换为uint64_t *并将检测到的变量写入其中。我确保通过检查变量是否小于或等于lim
  4. ,可以将检测到的变量写入变量

    这是允许的吗?

    代码:

    #include <stdio.h>
    #include <inttypes.h>
    #include <limits.h>
    #include <stdlib.h>
    
    static int str_to_uint(uint64_t *tar, const char *str, const uint64_t lim) {
        char *eptr = NULL;
        unsigned long long int temp = 0;
    
        if (str == NULL) {
            printf("str is a NULL pointer\n");
            return -1;
        }
    
        temp = strtoull(str, &eptr, 10);
        if (temp == 0 && eptr == str) {
            printf("strtoull() conv err, %s\n", str);
            return -1;
        } else if (temp > lim) {
            printf("strtoull() value to big to contain specified limit, %s\n", str);
            return -1;
        } else {
            *tar = temp;
        }
    
        return 0;
    }
    
    int main() {
        int ret;
    
        uint8_t a;
        uint16_t b;
        uint32_t c;
        uint64_t d;
    
        ret = str_to_uint((void *)&a, "22", UINT8_MAX);
        if (ret != 0) {
            exit(1);
        }
    
        ret = str_to_uint((void *)&b, "22", UINT16_MAX);
        if (ret != 0) {
            exit(1);
        }
    
        ret = str_to_uint((void *)&c, "22", UINT32_MAX);
        if (ret != 0) {
            exit(1);
        }
    
        ret = str_to_uint((void *)&d, "22", UINT64_MAX);
        if (ret != 0) {
            exit(1);
        }
    
        printf("a = %"PRIu8"\nb = %"PRIu16"\nc = %"PRIu32"\nd = %"PRIu64"\n", a, b, c, d);
    
        exit(0);
    
    }
    

2 个答案:

答案 0 :(得分:3)

不,当然你不能这样做。

如果我这样称呼你的功能:

uint8_t my_little_value;
str_to_uint(&my_little_value, "4711", sizeof my_little_value);

然后你做

uint64_t *user_value = tar;
*user_value = ...;

Boom,你已经覆盖了一堆你不允许触摸的字节。当然你知道这个,因为我告诉你变量的大小,你说你确定&#34;但是我不知道如果你的方法将是你的方法你打算怎么做将tar视为uint64_t *

我不明白为什么你不能像strtoul()那样只返回转换后的号码。这使得处理存储位置和潜在精度之间不匹配的责任代表了它所属的用户(甚至编译器!)上的转换数。您提出的API非常容易出错并且难以理解。

答案 1 :(得分:0)

在这行代码中:

*tar = temp;

您正在将8个字节的数据写入可能小于8个字节的变量。您需要单独处理每个大小,例如1个字节:

*(uint8_t *) tar = temp;