将一个字节的位写入bin文件

时间:2015-04-09 18:56:47

标签: c

所以我试图将结构写入二进制文件。它完美地工作,直到我只编写一部分字节。对于data_offset,reserved和ctl_bit,我只想将最后4,6,6位写入二进制文件。我不确定我哪里出错了。

struct tcp_head
{
    unsigned short  source_port;    //16 bits
    unsigned short  dest_port;      //16 bits
    unsigned int    seq_num;        //32 bits
    unsigned int    ack_num;        //32 bits
    unsigned char   data_offset;    //4 bits
    unsigned short  reserved;       //6 bits
    unsigned short  ctl_bit;        //6 bits
    unsigned short  window;         //16 bits
    unsigned short  checksum;       //16 bits
    unsigned short  urgent_point;   //16 bits
};

当我编写文件时,我试图使用逐位运算符进行混合使用。

    FILE *filePtr = fopen(filename, "wb");
    int i;

    if (!filePtr)
    {
        printf("\nError while writing file\n");
        exit(1);
    }

    (*temp).data_offset = (*temp).data_offset << 4;
    (*temp).reserved = (*temp).reserved  << 10;
    (*temp).ctl_bit = (*temp).ctl_bit  << 10;


    fwrite(&(temp->dest_port), sizeof((*temp).dest_port), 1, filePtr);
    fwrite(&(temp->source_port), sizeof((*temp).source_port), 1, filePtr);
    fwrite(&(temp->seq_num), sizeof((*temp).seq_num), 1, filePtr);
    fwrite(&(temp->ack_num), sizeof((*temp).ack_num), 1, filePtr);
    fwrite(&(temp->data_offset), sizeof((*temp).data_offset), 1, filePtr);
    fwrite(&(temp->reserved),sizeof((*temp).reserved), 1, filePtr);
    fwrite(&(temp->ctl_bit), sizeof((*temp).ctl_bit), 1, filePtr);
    fwrite(&(temp->window), sizeof((*temp).window), 1, filePtr);
    fwrite(&(temp->checksum), sizeof((*temp).checksum), 1, filePtr);
    fwrite(&(temp->urgent_point), sizeof((*temp).urgent_point), 1, filePtr);



    fclose(filePtr);

2 个答案:

答案 0 :(得分:1)

你说:

  

我只想将最后4,6,6位写入二进制文件。

你的代码确实:

(*temp).data_offset = (*temp).data_offset << 4;
(*temp).reserved = (*temp).reserved  << 10;
(*temp).ctl_bit = (*temp).ctl_bit  << 10;

(*temp).data_offset << 4;稍微偏移了4.您需要的是将除最后一个之外的所有位清零。您可以通过使用:

(*temp).data_offset = (*temp).data_offset & 0x0F;

同样,您需要使用:

(*temp).reserved = (*temp).reserved  & 0x3F;
(*temp).ctl_bit = (*temp).ctl_bit & 0x3F;

除了最后6位之外,这将把所有位清零。

创建存储转换值并保存转换值的临时变量可能更好。否则,您正在修改对象而无法恢复到原始状态。

答案 1 :(得分:0)

当尝试编写精确的二进制块(如TCP头)时,通常最好先将结构成员复制到缓冲区中,然后再写入缓冲区。这不仅可以让您移动单个位,还可以处理字节序:

// Need htons(), etc.
#include <arpa/inet.h>
// Need uint16_t, etc.
#include <stdint.h>

. . .

unsigned char buf[20];

*(uint16_t *)buf = htons(temp->source_port);
*(uint16_t *)(buf + 2) = htons(temp->dest_port);
*(uint32_t *)(buf + 4) = htonl(temp->seq_num);
*(uint32_t *)(buf + 8) = htonl(temp->ack_num);
*(uint16_t *)(buf + 12) = ((temp->data_offset & 0x0F) << 12) |
                          ((temp->reserved & 0x3F) << 6) |
                          (temp->ctl_bit & 0x3F);
*(uint16_t *)(buf + 14) = htons(temp->window);
*(uint16_t *)(buf + 16) = htons(temp->checksum);
*(uint16_t *)(buf + 18) = htons(temp->urgent_point);

现在buf是一个格式正确的网络顺序TCP标头(假设您的结构是“主机”顺序),并且可以写成一个字节块。