C中大小整数的算术和按位操作

时间:2014-04-17 13:48:36

标签: c int bit-manipulation

当你进行基本算术和按位运算时,我对C语言如何处理不同大小的int有点困惑。如果在这种情况下会发生什么:

int8_t even = 0xBB;
int16_t twice = even << 8;
twice = twice + even; 

如果我走另一条路并试图将16位int添加到8位,该怎么办?是正常的int声明动态?我为什么要指定尺寸?当我添加到0xFF的8位整数时会发生什么?

2 个答案:

答案 0 :(得分:3)

正如我在评论中提到的,在算术运算期间,所有内容都会被提升为至少一个int。

这是一个示例程序,用于演示:

main(){
    struct {
        char x : 1;
    }t;
    t.x = 1;
    int i = t.x << (sizeof i * 8 - 1);
    printf("i = %x\n",i);
}

t.x只有一位,但在这个操作中,它一直被提升为一个整数来给出输出:

i = 80000000

另一方面,如果我们添加行

long long j = t.x << (sizeof j * 8 - 1)

gcc给了我警告:

warning: left shift count >= width of type [enabled by default]

如果我走了另一条路并尝试将16位int添加到8位?

所有算术都以整数精度(可能是32位)完成,然后结果的低8位将存储在8位数中。

普通的int声明是动态的吗?

没有。它在实现上的固定宽度(可能是你的32位)。

为什么我要指定尺寸?

也许你有空间限制。也许您的算法可以使用特定大小的整数。也许你真的想要处理uint16_t(Z_65536)提供的一些模数字段。

当我添加到0xFF的8位整数时会发生什么?

此处的促销并不重要,8位结果将为0xFE。如果你要将结果存储在一个16位的数字中,那么结果将是0x1FE(除非你的实现中的int&#39; s只有8位。除了一些深奥的嵌入式应用程序之外,这是极不可能的)。

修改

我在这里写了关于无符号约定,因为你将数字表示为0xFF似乎是指无符号数(在K&amp; R C中0xFF实际上是无符号文字)。如果你实际上指的是等于-1的带符号的8位值0xFF,那么你的问题就变得微不足道了。无论整数有多大,它总是应该能够表示-1,以及-1 + (-1) = -2(你实际上只需要两位代表这些数字)。

答案 1 :(得分:0)

正常“int”不是动态的,但在编译器中并不常见;它是您正在编译的CPU最方便的大小。如果你有某些原因(网络协议,文件格式等),你可能想要指定一个大小,为什么你真正关心表示。

在您的问题答案下面的练习答案:


您的答案可以在C11最终草案规范中找到(2011年10月批准,但“最终”文件不是免费的):http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

第一个相关部分是6.3.1.1转换:算术操作数:布尔,字符和整数,从第50页开始

  

如果int可以表示原始类型的所有值(受宽度限制,对于位字段),则该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销。所有其他类型都不会被整数促销更改。

     

整数促销保留包括符号在内的值。如前所述,“普通”char是否被视为已签名是实现定义的。

本质上,整数类型都被提升为至少int,并且可能比任何操作数的排名大于该值的大小都更大。它们通常会被签名,但如果任一操作数的类型的范围大于int,则保持无符号。

有很多内容专门定义了如何执行转换,并且编写了哪些类型的规则比其他类型“更高级别”(更大),然后我们达到了6.3.1.8中的真实内容:通常的算术转换:

  

许多期望算术类型操作数的运算符会导致转换并产生结果   以类似的方式输入类型。目的是确定操作数的公共实型   和结果。对于指定的操作数,将转换每个操作数,而不更改类型   域,对应的实类型是常见的实类型。除非   另外明确说明,常见的真实类型也是相应的实际类型   结果,其类型域是操作数的类型域,如果它们是相同的,   否则复杂。这种模式称为   通常的算术转换

......关于花车的一些东西......

  

否则,将对两个操作数执行整数提升。然后将以下规则应用于提升的操作数:

     

如果两个操作数具有相同的类型,则不需要进一步转换。否则,如果两个操作数都具有有符号整数类型或两者都具有无符号整数类型,则具有较小整数转换等级类型的操作数将转换为具有更高等级的操作数的类型。否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的等级,则操作数与   有符号整数类型将转换为具有无符号整数类型的操作数类型。

     

否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为带有符号整数的操作数的类型类型。

     

否则,两个操作数都将转换为无符号整数类型,对应于带有符号整数类型的操作数类型。


  

int8_t even = 0xBB;

0xBB形成为int类型的常量(0x000000BB),然后被截断为int8_t

  

int16_t两次=偶数&lt;&lt; 8;

even的值是从int8_t扩展到int的符号,变成0xFFFFFFBB(如果我假设int在这台机器上是32位) 值8形成为int类型 这些类型匹配,因此不会进行进一步的转换 运算符&lt;&lt;执行(现在类型匹配),产生0xFFFFBB00 此值被截断以适合int16_t,产生0xBB00

  

两次=两次+均匀;

两次的值是从int16_t扩展到int的符号,产生0xFFFFBB00(-17664) even的值是从int8_t扩展到int的符号,产生0xFFFFFFBB(-69) 添加这些值,产生0xFFFFBABB(-17733) 然后截断该值以适合int16_t,产生0xBABB

  

当我添加到0xFF的8位整数时会发生什么?

它们都被符号扩展为int,产生0xFFFFFFFF,然后添加产生0xFFFFFFFE。这可能会也可能不会被截断,具体取决于您存储它的位置。


编译器当然可以自由地注意到,这些扩展/截断的大部分内容都是毫无价值的繁忙工作,因为不保留输出位,并优化它。但结果必须“好像”,如果已经做了很长的事情。