You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言write系统调用写入位置异常原因咨询

问题:C程序写入字节位置不符合预期的原因?

我编写了一个简单的C程序,接收四个命令行参数:文件名、起始位置、长度和字节值;打开指定文件进行写入,并从指定位置开始,将文件中指定长度的段填充为指定字节值。程序以块为单位写入(当前为调试目的设置块大小为4字节)。

程序代码如下:

/* fill_file_w_byte_val.c */

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

int block_size = 4;

void error_handling(int res, const char *file_name)
{
    if (res == -1) {
        perror(file_name);
        exit(1);
    }
}

void write_n_blocks_of_bytes_to_file(
    const char *file_name, int fd, void *mem,
    int block_size, int num_of_blocks, int byte_val
)
{
    int i, res;
    mem = malloc(sizeof(char) * block_size);
    memset(mem, byte_val, block_size);
    for (i=num_of_blocks; i > 0; i--) {
        res = write(fd, mem, block_size);
        error_handling(res, file_name);
    }
    free(mem);
}

int main(int argc, char **argv)
{
    char *file_name, *mem = NULL;
    int len, byte_val, num_of_blocks, fd, res, reminder;
    long start_pos;
    if (argc != 5) {
        printf("Wrong number of arguments: %d. It must be %d", argc-1, 4);
        return 1;
    }
    file_name = argv[1];
    fd = open(file_name, O_WRONLY);
    error_handling(fd, file_name);
    start_pos = atoi(argv[2]);
    res = lseek(fd, start_pos, SEEK_SET);
    error_handling(res, file_name);
    len = atoi(argv[3]);
    byte_val = atoi(argv[4]);
    if ((byte_val < 0) || (byte_val > 255)) {
        printf("Wrong value of byte: %d. It must be from 0 to 255.", byte_val);
        return 1;
    }
    num_of_blocks = len / block_size;
    if (num_of_blocks > 0)
        write_n_blocks_of_bytes_to_file(
            file_name, fd, mem, block_size, num_of_blocks, byte_val
        );
    reminder = len % block_size;
    if (reminder != 0)
        write_n_blocks_of_bytes_to_file(
            file_name, fd, mem, reminder, 1, byte_val
        );
    res = close(fd);
    error_handling(res, file_name);
    return 0;
}

运行会话:

fedor@fedor-Latitude-E7250:~/c$ hexdump test.bin
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
000001c
fedor@fedor-Latitude-E7250:~/c$ ./fill_file_w_byte_val test.bin 1 2 255
fedor@fedor-Latitude-E7250:~/c$ hexdump test.bin
0000000 ff00 00ff 0000 0000 0000 0000 0000 0000
0000010 0000 0000 0000 0000 0000 0000          
000001c

疑问:为何程序写入的是第0和第3字节,而非预期的第1和第2字节?


原因分析与解决方案

核心原因:hexdump的默认显示方式造成误解

hexdump默认以16位(2字节)为单位分组显示,并且会把每组内的两个字节按小端字节序解析成16位整数后输出。也就是说:

  • 内存中连续的两个字节[0x00, 0xff]会被解析为16位整数0xff00,并显示为ff00
  • 内存中连续的两个字节[0xff, 0x00]会被解析为16位整数0x00ff,并显示为00ff

回到你的运行结果:
执行命令后hexdump输出的ff00 00ff,对应的实际内存字节序列是:

字节0: 0x00, 字节1: 0xff, 字节2: 0xff, 字节3: 0x00

这完全符合你的预期——程序确实正确写入了第1和第2字节(值为0xff),只是hexdump的默认显示方式让你误判了位置。

验证方法

使用hexdump -C参数(按字节逐列显示)查看文件,就能直观看到每个字节的实际值:

hexdump -C test.bin

此时你会看到类似如下输出,清晰显示第1、2字节为ff:

00000000  00 ff ff 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0000001c

程序的潜在优化点

  1. 起始位置的类型转换:start_pos是long类型,但你用atoi转换,当起始位置超过int范围时会出错,建议改用atol或strtol:
    start_pos = atol(argv[2]);
    
  2. 文件打开方式:当前用O_WRONLY,如果文件不存在会直接报错,若需要自动创建文件,可添加O_CREAT参数,并指定权限:
    fd = open(file_name, O_WRONLY | O_CREAT, 0644);
    

内容的提问来源于stack exchange,提问作者Fyodor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 11:13:12