8位输入给出奇怪的行为,因为16/32位给出了小Endian / Big Endian

时间:2013-01-15 22:36:08

标签: c pointers struct network-programming bit-manipulation

我有这样的C结构......

struct icmp_prefixopt {
    u_int8_t        icmpopt_type;
    u_int8_t        icmpopt_len;
    u_int8_t        prefixlen;
    u_int8_t        lflag:1;
    u_int8_t        aflag:1;
    u_int8_t        reserved:6;

};

我在同一个模块中为这样的成员提供了值 -

   popt= (struct icmp_prefixopt *)
                    malloc(sizeof(struct icmp_prefixopt));

  popt->icmpopt_type = 3;
  popt->icmpopt_len = 4;
  popt->prefixlen = (u_int8_t)strtoul(arg, (char **)NULL, 0);

     arg = index(arg, '+');
            if (arg) {
                    ++arg;
                    popt->lflag = ((u_int8_t)strtoul(arg, (char **)NULL, 0))&1;
            }


     arg = index(arg, '+');
            if (arg) {
                    ++arg;
                    popt->aflag = ((u_int8_t)strtoul(arg, (char **)NULL, 0))&1;
            }


     arg = index(arg, '+');
            if (arg) {
                    ++arg;
                 popt->reserved = 32;  //((u_int8_t)strtoul(arg, (char **)NULL, 0))<<2;
            }

其中arg是传递给该模块的命令行参数。

现在以十六进制格式执行后查看结构的内容 - &gt;

  03 04 20 81

   icmpopt_type: seems fine
   icmpopt_len: seems fine
   prefixlen: seems fine

但其构成字节中的其他3个字段的位看起来相反 -

  lflag:1; aflag:1; reserved:6

所以应该是 - 10100000=A0但实际上它们是=>81=10000001

它给我带来了很多问题......

  1. 小端/大端有什么关系吗?

  2. 如果是,8位的htonl和htons等函数的对应部分。

  3. 如果不是,可能是什么问题或者我完全误解了什么?

  4. 什么是最好的方法?修改结构中这些字段的顺序
    本身或在这里应用一些有点操作符和位移位?

  5. 命令行提供的输入 -

        32+1+0+32 
    

    这个最后的32在这里没有任何意义,因为我已经在模块中修复了32个用于测试。 虽然我的实际目的也需要考虑这个领域。

    请尽快通过任何替代方法帮助我。

    提前完成。

    修改

    enter image description here

    这是我需要创建的实际结构,并且随着创建,需要为用户做出规定,通过GUI为所有字段指定值。 (现在只能通过linux命令行)。

    我想我现在已经让问题更加清晰了,但如果还需要更多信息,我会很乐意添加。

1 个答案:

答案 0 :(得分:5)

编译器如何选择打包位字段完全取决于实现。它不一定与字节序有任何关系。

htnol(和类似的)不适用于位字段。如果您需要保证订单,则需要自己手动打包uint8_t。例如:

struct icmp_prefixopt {
    u_int8_t        icmpopt_type;
    u_int8_t        icmpopt_len;
    u_int8_t        prefixlen;
    u_int8_t        stuff;
}

...

popt->stuff = (lflag << 7) | (aflag << 6);

当然,在实践中,你应该使用合理的#define而不是魔术数字(6和7)。你可以决定将它包装在一堆setter和getter函数中。