关于左移的缺陷

# cat test.c 
#include <stdio.h>
#include <stdint.h>

void
func_1(void)
{
    uint32_t mask = 0xFFFFFFFF;
    uint32_t masklen = 0;

    printf("mask: %x\n", (mask << (32 - masklen)));
    printf("mask: %x\n", (0xFFFFFFFF << (32 - masklen)));
    printf("mask: %x\n", (0xFFFFFFFF << 32));
}
int
main(int argc, char *const argv[])
{
    func_1();

    return 0;
}

结果:

[root@localhost ~/test/test_17]
# gcc test.c 
test.c: In function ‘func_1’:
test.c:12:5: warning: left shift count >= width of type [enabled by default]
     printf("mask: %x\n", (0xFFFFFFFF << 32));
     ^
[root@localhost ~/test/test_17]
# ./a.out 
mask: ffffffff
mask: ffffffff
mask: 0

系统信息:

# uname -a
Linux localhost.localdomain 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

其它资料:http://blog.chinaunix.net/uid-23629988-id-127318.html
Intel的指令手册

SAL/SAR/SHL/SHR—Shift (Continued)——32位机
Description
These instructions shift the bits in the first operand (destination operand) to the left or right by
the number of bits specified in the second operand (count operand). Bits shifted beyond the
destination operand boundary are first shifted into the CF flag, then discarded. At the end of the
shift operation, the CF flag contains the last bit shifted out of the destination operand.
The destination operand can be a register or a memory location. The count operand can be an
immediate value or register CL. The count is masked to five bits, which limits the count range
to 0 to 31. A special opcode encoding is provided for a count of 1.

这下真相大白了。原来在32位机器上,移位counter只有5位。那么当执行左移32位时,实际上就是左移0位。
那么这个1ul << move_step就相当于1ul<<0。那么value2自然就是1了。

到此,我们虽然已经知道整个儿的来龙去脉了,可是不能不说Intel的移位指令是有着陷阱的。因为在除了在Intel这个手册中说明了这个情况,在其它的汇编语言的资料中,从没有提及过这个情况。有的朋友可能说了,之前gcc已经给了一个“test.c:8: warning: left shift count >= width of type”这样的警告了啊,已经对这个情况做了提示。关于这个warning,如果代码再复杂一些,移位的个数不再是一个常量,gcc肯定是无法检测出来的。所以,当我们需要做移位处理时,一定要注意是否超出了32位(64位机则是64位)。

另外,对于gcc的处理,我也有一点意见。当1ul<<32时,gcc自己预处理的结果与进行运算的结果不符,虽然它更符合用户的期望。但是,当用户开始使用常量时,结果是对的,一旦换成了变量,结果就不一样了。在大型的程序中,这样会让用户很难定位到问题的。

修改后的答案:

# cat test.c 
#include <stdio.h>
#include <stdint.h>

void
func_1(void)
{
    uint32_t mask = 0xFFFFFFFF;
    uint32_t masklen = 0;
    uint32_t ip = 12345678;
    uint32_t ip_net = 0;

    if (0 != masklen) {
        printf("mask: %x\n", (mask << (32 - masklen)));
        ip_net = ip & (mask << (32 - masklen));
    } else {
        ip_net = 0; 
    }
}
int
main(int argc, char *const argv[])
{
    func_1();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值