问一个 C 语言关于文件操作的问题,如何将 uint32_t 数据写进二进制文件, 4byte 对齐?

2020-08-24 23:59:21 +08:00
 ReputationZh
fwrite 的第一个参数是 char 类型,好像不支持啊?应该用什么方法写入。
2754 次点击
所在节点    Linux
21 条回复
dangyuluo
2020-08-25 00:01:56 +08:00
在不考虑字节序的情况下,盲猜每次读 8bit 再写入?
louettagfh
2020-08-25 00:12:15 +08:00
1. open 的时候加参数 binary
2. 写对齐没有意义
zwy100e72
2020-08-25 00:27:20 +08:00
第一个不是 char 类型,而是指向 buffer 的一个指针;第二个参数是 buffer 的长度,因此要达到写 4 bytes (sizeof(uint32_t))的效果,你需要 ( https://godbolt.org/z/zMMWb3 ):

```c
#include <cstdint>
#include <cstdio>

void f(uint32_t i) {
FILE* fp = fopen("path/to/file.bin", "wb");
fwrite(&i, sizeof(i), 1, fp);
fclose(fp);
}
```

https://en.cppreference.com/w/c/io/fwrite
XiaoxiaoPu
2020-08-25 00:27:54 +08:00
需要先把 uint32_t 转化成 4 个 char,这里涉及大小端的问题,可以搜一下「大小端」
zwy100e72
2020-08-25 00:29:14 +08:00
对齐与否之前只有在内存中才有必要对齐,更何况现在不对齐的内存访问也已经很快了,你没有必要对齐
baoshuo
2020-08-25 01:00:02 +08:00
对齐感觉没用
Tony042
2020-08-25 02:12:13 +08:00
不知道 C 怎么做,C++内置了关键字 直接 alignas(4) uint_32 即可
laminux29
2020-08-25 03:29:20 +08:00
C 语言层次,我不建议你去主动对齐,因为这个层次的文件读写,本质是把 buffer 交给 OS 去处理的,最后这些 buffer data 写到存储设备时,是否进行对齐 io,是由 OS 来决定的。

OS 在把数据 flush 到存储设备上的优化动作,可不止对齐一种。
yngzij
2020-08-25 07:46:39 +08:00
我记得只有在 malloc 的时候对齐吧
chinuno
2020-08-25 08:37:12 +08:00
(char*)&num 直接转成 char 类型数组写入 4 个字节就行。本身 uint32_t 就是 4 个字节也不用考虑对齐问题吧。读的时候四个四个读把 char 数组转回 uint32_t 也不用考虑字节序的问题了
shuax
2020-08-25 08:52:29 +08:00
uint32_t 不就是 4 个字节,还对齐什么
heguangyu5
2020-08-25 09:32:36 +08:00
mmap 要写入的文件,然后 align 要写入的地址,然后 memcpy.

类似这样:

fd = open()
addr = mmap()
ptr = addr + offset
ptr = align()
memcpy(ptr, &int_var, sizeof(int))
yolee599
2020-08-25 09:33:13 +08:00
要考虑大端还是小端储存
May725
2020-08-25 12:14:42 +08:00
以 binary 形式打开文件,写多少个字节就是多少个字节
Chenamy2017
2020-08-25 12:55:45 +08:00
看#3,怎么写进去将来用的时候怎么读出来就行了。
CRVV
2020-08-25 13:04:14 +08:00
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

fwrite 的第一个参数明明是 const void* 类型

直接
uint32_t x;
fwrite(&x, 4, ...)
应该就能用

另外,没有理解楼主说的 对齐 是指什么,如果从头开始写,每次写 4 bytes,那当然是对齐到 4 bytes 上的
wizardoz
2020-08-25 13:13:34 +08:00
我感觉直接写就是对齐的,为此我还特意写代码测试了一下:
#include <stdio.h>

typedef struct {
char a;
int b;
char c;
} Test_t;

int main(int argc, char* argv[]) {
Test_t test = {
.a = 1,
.b = 2,
.c = 3
};

FILE *fp = fopen("/tmp/data.bin", "wb");
if (fp != NULL) {
fwrite(&test, sizeof(test), 1, fp);

fclose(fp);
}
return 0;
}

文件内容:
00000000: 0156 0000 0200 0000 037f 0000 0a .V...........
wizardoz
2020-08-25 13:16:31 +08:00
你写到文件是几字节对齐应该是与你的数据在内存中是几字节对齐一致的,毕竟写的时候只是把内存原样写进去。
如果你设置了内存 1 字节对齐,那么写到文件也是 1 字节对齐的。
CRVV
2020-08-25 13:21:18 +08:00
@wizardoz

struct 里面的 field 都会 self-align,把 int b 放到 char a 前面,char c 就不会 align 到 4 bytes 上了。
ReputationZh
2020-08-27 09:26:04 +08:00
@zwy100e72 感谢大佬,不过我有个疑问,假设我的数据类型是 uint32_t,但是我 fwrite 的时候大小填写的 5 或者 8 (不为 uint32_t 的 4 ),我写进去的数据是真实的吗?多余的字节数会产生什么异变吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/701108

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX