V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
leeyiw
V2EX  ›  C

C 读 16 bit 大端数的一个小问题

  •  
  •   leeyiw · 2015-05-22 18:38:29 +08:00 · 1288 次点击
    这是一个创建于 3458 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我的程序在 Ubuntu 上就能正常工作,最近在 CentOS 上运行就会出现莫名其妙的 Bug。如下:

    原始代码:
    static inline uint16_t
    up_packet_read_uint16_be(up_packet_t *p)
    {
    return (*(p->pointer++) << 8) | *(p->pointer++);
    }

    函数只想读一个 16 Bit 大端数返回,在 Ubuntu 上, 能够正常工作, 在 CentOS 上,函数只读了第一个字节,并没有读第二个字节。谁能帮忙看下?非常感谢。

    PS,up_packet_t 定义如下:
    struct up_packet_s {
    uint8_t *buffer;
    uint8_t *pointer;
    size_t length;
    size_t capacity;
    };
    第 1 条附言  ·  2015-05-22 19:45:49 +08:00
    对于问题,主要的现象是 pointer 只自增了 1
    第 2 条附言  ·  2015-05-22 21:36:04 +08:00
    谢谢大家,下次不写这么糟糕的代码了 :)
    19 条回复    2015-05-23 22:58:17 +08:00
    Septembers
        1
    Septembers  
       2015-05-22 18:46:17 +08:00
    cat /proc/cpuinfo
    ShadowStar
        2
    ShadowStar  
       2015-05-22 19:05:44 +08:00
    未定义
    choury
        3
    choury  
       2015-05-22 19:20:09 +08:00 via Android
    一个语句放两个++,结果是不确定的,和编译器实现有关
    acros
        4
    acros  
       2015-05-22 19:24:06 +08:00
    这不是触发短路求值了么?

    我去VS里面验证下,目前没gcc····
    acros
        5
    acros  
       2015-05-22 19:30:48 +08:00
    木有试出来······

    三楼说的应该是对的,我记得code warrior编译器对这种的处理就和vs相反的。
    xylophone21
        6
    xylophone21  
       2015-05-22 19:33:00 +08:00   ❤️ 1
    只读了第一个字节,并没有读第二个字节。这个怎么解释?
    0x12 0x34 ==> 0x1200? 0x0034? 0x3412?

    1. *(p->pointer++) << 8 溢出?
    2. C规范定义中没有说|操作的左右顺序,但也没有说行为是未定义的。不过讲||时,它用了一个unlike,这种东西跟优先级差不多,虽然有规则,但没几个人记得住,用()规避的好。

    6.5.12 Bitwise inclusive OR operator
    Syntax
    1 inclusive-OR-expression: exclusive-OR-expression
    inclusive-OR-expression | exclusive-OR-expression
    Constraints
    2 Each of the operands shall have integer type.
    Semantics
    3 The usual arithmetic conversions are performed on the operands.
    4 The result of the | operator is the bitwise inclusive OR of the operands (that is, each bit in the result is set if and only if at least one of the corresponding bits in the converted operands is set).


    6.5.14 Logical OR operator
    Syntax
    1 logical-OR-expression: logical-AND-expression
    logical-OR-expression || logical-AND-expression
    Constraints
    2 Each of the operands shall have scalar type.
    Semantics
    3 The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.
    4 Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.
    xylophone21
        7
    xylophone21  
       2015-05-22 19:35:23 +08:00
    @choury 这个说法并不准确

    if( *p++ || *p++ )

    行为是一定的
    leeyiw
        8
    leeyiw  
    OP
       2015-05-22 19:45:10 +08:00 via iPhone
    @xylophone21 我的意思是pointer只自增了1
    leeyiw
        9
    leeyiw  
    OP
       2015-05-22 19:46:44 +08:00 via iPhone
    @xylophone21 你说的是逻辑或,我说的是按位或。
    leeyiw
        10
    leeyiw  
    OP
       2015-05-22 19:47:36 +08:00 via iPhone
    @choury 行为确实感觉未定义,但是只自增了 1 感觉还是有点奇怪~
    xylophone21
        11
    xylophone21  
       2015-05-22 19:48:28 +08:00
    @leeyiw 这没有道理,除非你把 “|” 写成了 "||" 。
    leeyiw
        12
    leeyiw  
    OP
       2015-05-22 19:56:27 +08:00 via iPhone
    @xylophone21 写的确实如上面代码所述,所以感觉很诡异
    choury
        13
    choury  
       2015-05-22 20:21:11 +08:00 via Android
    @xylophone21 我只是对楼主的这个语句


    @leeyiw 这种情况如果想要准确知道发生了什么,只需要看汇编代码即可
    zhicheng
        14
    zhicheng  
       2015-05-22 20:26:05 +08:00 via Android
    教科书似的“未定义行为”。
    Monad
        15
    Monad  
       2015-05-22 22:46:27 +08:00
    §5/4.1 Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.
    另外这种东西不应该是直接(int16_t*)p->pointer然后ntohs最后p->pointer += 2么
    leeyiw
        16
    leeyiw  
    OP
       2015-05-23 11:56:15 +08:00
    @Monad 谢谢,这样很方便
    xylophone21
        17
    xylophone21  
       2015-05-23 22:42:26 +08:00
    @Monad 他的数据是bigend,而现在的cpu以littleend的居多,你确定这样可以?
    xylophone21
        18
    xylophone21  
       2015-05-23 22:43:04 +08:00
    @leeyiw 那只能建议看汇编了
    Monad
        19
    Monad  
       2015-05-23 22:58:17 +08:00
    @xylophone21 就因为是Big Endian所以采用ntohs了, Network Byte Order 本来就是Big Endian的嘛
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1008 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:44 · PVG 03:44 · LAX 11:44 · JFK 14:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.