V2EX 首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

踩了个陷阱: Python bitwise ~ vs. C bitwise ~

  •  1
     
  •   justou · 3 天前 · 551 次点击

    有如下 C 代码:

    #include <stdio.h>
    
    int main()
    {
        int x = 0x87654321;
        int mask = 0xFF;                            
    
        printf("0x%08x\n", ~mask);
        printf("0x%08x\n", x & mask);    
        printf("0x%08x\n", x ^ ~mask);   
        printf("0x%08x\n", x | mask); 
        return 0;
    }
    

    输出:

    0xffffff00
    0x00000021
    0x789abc21
    0x876543ff
    

    改成对应的 python 代码:

    x = 0x87654321
    mask = 0xFF
    print("0x%08x" % (~mask))
    print("0x%08x" % (x & mask))
    print("0x%08x" % (x ^ ~mask))
    print("0x%08x" % (x | mask))
    

    输出:

    0x-0000100
    0x00000021
    0x-876543df
    0x876543ff
    

    请问 python 输出与 C 输出不一致的原因是什么,能否修改 python 代码使其与 C 输出一致?

    6 回复  |  直到 2017-06-20 14:10:35 +08:00
        1
    pright   3 天前   ♥ 1
    import ctypes

    print("0x%08x" % (ctypes.c_uint(~mask).value))
        2
    enenaaa   3 天前   ♥ 1
    好像是被当成有符号数打印了。
    试一下 &0xffffffff。这样
    print("0x%08x" % ((~mask)&0xffffffff))
        3
    popstk   3 天前   ♥ 1
    <code>def foo(n, size=32):
    return ((1<<size)-1)&n


    x = 0x87654321
    mask = 0xFF
    print("0x%08x" % foo(~mask))
    print("0x%08x" % foo(x & mask))
    print("0x%08x" % foo(x ^ ~mask))
    print("0x%08x" % foo(x | mask))
    </code>

    https://wiki.python.org/moin/BitwiseOperators
        4
    NoAnyLove   3 天前   ♥ 2
    因为 Python 的 int 是无限长度的,如果对一个正整数取反,会变成负数,你可以认为符号位是无限长度的 1:

    ```
    >>> mask = 0xFF
    >>> bin(mask)
    '0b11111111'
    >>> ~mask
    -256
    >>> bin(~mask)
    '-0b100000000'
    ```

    `bin(~mask)`返回结果'-0b100000000',前面的`-0`就是相当于无限长度的符号位,如果用 Two ‘ s Complement 来表示就全是 1.

    解决这个问题也很简单,将结果按位与 0xFFFFFFFF (刚好 32 位 bit )运算,就可以消除掉超过 32 位的无限长度的符号位。

    ```
    >>> ~mask & 0xFFFFFFFF
    4294967040
    >>> hex(_)
    '0xffffff00'
    ```
        5
    justou   3 天前
    感谢楼上各位,4L 给了个很好的解释
        6
    pright   3 天前
    这里不一致的原因其实就是 C 的 printf 的%x 对应的是 unsigned hexadecimal integer,而 python 的 print 的%x 对应的是 signed hexadecimal integer。
    DigitalOcean
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   鸣谢   ·   2188 人在线   最高记录 2607   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.7.5 · 50ms · UTC 08:44 · PVG 16:44 · LAX 01:44 · JFK 04:44
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1