c - 我真的不知道为什么移位在一种情况下有效,但在另一种情况下无效

标签 c bit-shift

所以我正在做一些位移,我遇到了以下问题,如果能得到答案,我将非常感激:

作为参数,我可以传递 1 个字节的大小。

前 4 位代表一个分子。 最后4位代表分母。

以下代码有效并给出正确的输出:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char** argv)
{
    for(int i = 1; i < argc; i++)
    {
        unsigned char numerator = atoi(argv[i]);
        numerator = (numerator >> 4);
        numerator = (numerator << 4);

        unsigned char denominator = atoi(argv[i]);
        denominator = (denominator << 4);
        denominator = (denominator >> 4);
        printf("%d/%d\n", numerator, denominator);
    }

    return 0;
}

但是如果我像这样替换位移部分,分母给出与分子相同的输出:

unsigned char numerator = atoi(argv[i]);
        numerator = (numerator >> 4) << 4;

unsigned char denominator = atoi(argv[i]);
        denominator = (denominator << 4) >> 4;

示例输入为:

./test 1
./test 16

给出的输出:

0/1
16/16

预期输出:

0/1
16/0

提前感谢任何形式的帮助。

最佳答案

在 C 中计算算术表达式时,任何小于 int 的整数类型晋升为int在执行计算之前。


所以这段代码:

unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4);
denominator = (denominator >> 4);

结果如下(每个框代表4位,框内文字为十六进制数字):

enter image description here

注意赋值 denominator = (denominator << 4);强制编译器将值转换回 unsigned char .然后在下一行代码中,编译器需要提升 unsigned char返回 int .


但是这段代码:

unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4) >> 4;

跳过转换回unsigned char第二次晋升为int .所以顺序是:

enter image description here

请注意,最终值与原始值相同,因为移位是使用 32 位执行的,并且没有从 32 位值的左侧移出任何内容。


分子没有同样的问题。因为分子先右移,所以右边的位会丢失。促销至int对结果没有影响。这是分子的顺序:

enter image description here

关于c - 我真的不知道为什么移位在一种情况下有效,但在另一种情况下无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61433792/

相关文章:

c - Sublime Text在Windows中编译多个文件

c - 通过管道发送结构而不丢失数据

c++ - 使用 system() 执行命令返回返回值的 256 倍 (<< 8)。这有什么意义呢?

c++ - 从 8 位转换为 1 字节

go - 具有无符号值的位移给出有符号结果

c - 迭代动态分配的 char 数组

c - 测量上下文切换的时间

c - 我想了解 c 中 "printf"函数的工作原理。例如,对于下面代码中使用的打印语句,输出不同,为什么?

c# - 为什么我在 Powershell 和 C# 之间得到不同的结果

c - 从无符号int提取位的函数