通过传递的 uint32_t 数组指针在函数中正确使用 malloc

标签 c malloc uint32-t

我在函数中使用 malloc 时遇到困难,在该函数中我读取了一个包含 4 字节无符号整数的二进制文件,释放传递的数组引用,将其重新分配为新大小,然后尝试访问数组成员。我认为问题是由于 uint32_t 类型引起的,因为数组似乎被视为 8 字节整数数组而不是 4 字节整数数组。不确定我哪里出错了,可能是使用 malloc,IE 可能我需要指示它以与我正在做的不同的方式创建 uint32_t 类型,或者可能是其他方式。代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>

int filecheck (uint32_t **sched, int * count) {
    int v, size = 0;
    FILE *f = fopen("/home/pi/schedule/default", "rb");
    if (f == NULL) { 
        return 0; 
    } 
    fseek(f, 0, SEEK_END);
    size = ftell(f);
    fseek(f, 0, SEEK_SET);
    int schedsize = sizeof(uint32_t);
    int elementcount = size / schedsize;
    free(*sched);
    *sched = malloc(size);
    if (elementcount != fread(sched, schedsize, elementcount, f)) { 
        free(*sched);
        return 0;
    } 
    fclose(f);
// This works correctly and prints data as expected
    for (v=0;v<elementcount;v++) { 
        printf("Method 1 %02d %u \n", v, ((uint32_t*)sched)[v]);
    }

// This skips every other byte byt does not print any numbers > 32 bit unsigned
    for (v=0;v<elementcount;v++) { 
        printf("Method 2 %02d %u \n", v, sched[v]);
    }
// This treats the binary file as if it was 64 bit uints, printing 64 bit numbers
    for (v=0;v<elementcount;v++) { 
        printf("Method 3 %02d %lu \n", v, sched[v]);
    }
    *count = elementcount;
    return 1;
}

int main (){
    uint32_t *sched = NULL;
    int i, count = 0;
    if (filecheck(&sched, &count)) {
        for (i=0;i<count;i++) { // At the next line I get a segmentation fault
            printf("Method 4 %02d %u\n", i, sched[i]);
        }
    } else {
        printf("Error\n");
    }
    return 0;
}

我按要求添加了文件读取代码。尝试以我正在执行的方式访问 main() 中计划的数组将打印我正在读取的数据,就好像它是 8 字节整数一样。所以我猜 sched 被视为 64 位整数数组,而不是我定义的 32 位整数。我想这是因为我释放了它并再次使用了 malloc。但我相信我指示 malloc 它应该创建的类型是 uint32_t 所以我很困惑为什么数据没有被这样对待。

编辑:找到了一种使其工作的方法,但不确定它是否正确(方法 1)。这是将此数组视为 uint32_t 类型的唯一且最干净的方法吗?编译器当然应该知道我正在处理什么类型,而不必在我每次使用它时都强制转换它。

编辑:实际上,当我尝试在 main 中访问它时,出现段错误。我在代码中添加了一条注释来反射(reflect)这一点。我之前没有注意到这一点,因为我在几个地方使用 for print 循环来跟踪编译器如何查看数据。

编辑:不确定是否可以添加二进制数据文件。我是在十六进制编辑器中手工制作的,它的确切内容并不那么重要。在bin文件中,FF FF FF FF FF FF FF FF应该被读取为2个uint32_t类型,而不是1个64位整数。 Fread AFAIK 不关心这个,它只是填充缓冲区,但如果那是错误的,将被纠正。

TIA,皮特

最佳答案

// This works correctly and prints data as expected
    for (v=0;v<elementcount;v++) { 
        printf("Method 1 %02d %u \n", v, ((uint32_t*)sched)[v]);
    }

这不太对,因为sched是一个uint32_t**,而你分配给了*sched。还因为 %u 不是您打印 uint32_t 的方式。 首先取消引用 sched,然后应用数组索引访问。

你想要 printf("%02d %"PRIu32"\n", v, (*sched)[v]));

// This skips every other byte byt does not print any numbers > 32 bit unsigned
    for (v=0;v<elementcount;v++) { 
        printf("Method 2 %02d %u \n", v, sched[v]);
    }

是的,那是因为 sched[v] 是一个 uint32_t*,并且由于它是指针类型并且您可能在 64 位机器上运行,所以它是可能是 64 位...因此您将以 8 字节的增量而不是 4 字节的增量进行迭代,并尝试将指针打印为 %u。它也会越界,因为 8*10 大于 4*10,这很可能会导致段错误。

// This treats the binary file as if it was 64 bit uints, printing 64 bit numbers
    for (v=0;v<elementcount;v++) { 
        printf("Method 2 %02d %lu \n", v, sched[v]);
    }

这与第二个示例类似,只是您使用稍微更合适但仍然不正确的 %lu 进行打印。

您还需要将 fread() 转换为 *sched 而不是 sched,否则会导致 UB 和此当您尝试读取数组时很可能会导致段错误

此外,您在 main 中的 for 循环永远不应该运行,因为您没有将 count 设置为 filecheck 中的任何内容,因此它仍然应该为零(在没有 UB 的情况下) ,至少)。

其他评论:

  • 正如您刚刚了解到的,不要在 C 中转换 malloc() 的结果。
  • main() 应该返回一个值。 0 如果一切顺利。
  • 当然,您可以使用 fwrite() 将一些 uint32_t 作为字节写入文件。
  • 检查 malloc() 的结果是否成功。
  • 使用 size_t 作为 size_t 值而不是 int,并相应地打印 (%zu)。<

关于通过传递的 uint32_t 数组指针在函数中正确使用 malloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30115129/

相关文章:

c - 安全调整结构大小

c - 迭代 int 数组时,每个宏都会引发 "Segmentation fault"

c - 如何高效计算 2 的大幂?

c - 如何将多个结构体连续放入内存?

ios - 如何将 UIColor RGB 颜色转换为 uint32_t 值

c++ - 从uint32_t读取位

c - 如何实现动态共享内存大小调整?

字符指针和 malloc

c++ - 预期 malloc 函数的大小不同

c - include iostream 破坏 uint32_t 定义 (C)