首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C中大小ints的算术与位操作

问C中大小ints的算术与位操作
EN

Stack Overflow用户
提问于 2014-04-17 13:48:36
回答 2查看 159关注 0票数 2

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

代码语言:javascript
复制
int8_t even = 0xBB;
int16_t twice = even << 8;
twice = twice + even; 

如果我走另一条路,试图在8位中添加一个16位int,该怎么办?正常的int声明是动态的吗?为什么我要指定一个尺寸?当我将两个都是0xFF的8位ints相加时,会发生什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-17 14:15:19

正如我在评论中提到的,在算术过程中,每件事都被提升到至少一个int。

这里有一个示例程序来演示:

代码语言:javascript
复制
main(){
    struct {
        char x : 1;
    }t;
    t.x = 1;
    int i = t.x << (sizeof i * 8 - 1);
    printf("i = %x\n",i);
}

t.x只有一个位,但是在这个操作中,它一直被提升到一个整数,以提供输出:

代码语言:javascript
复制
i = 80000000

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

代码语言:javascript
复制
long long j = t.x << (sizeof j * 8 - 1)

gcc警告我:

代码语言:javascript
复制
warning: left shift count >= width of type [enabled by default]

,如果我走另一条路,试图在8位中添加一个16位int,该怎么办?

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

是正常的int声明动态?。

不是的。它是实现的固定宽度(可能是32位)。

为什么我要指定一个大小?

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

,当我将两个都是0xFF?的8位ints相加时会发生什么?

推广在这里不重要,8位的结果将是0xFE。如果要将结果存储在16位数字中,则结果将是0x1FE (除非您的实现中的int值只有8位)。这是非常不可能的,除了一些深奥的嵌入式应用程序)。

编辑

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

票数 2
EN

Stack Overflow用户

发布于 2014-04-17 14:22:40

普通的"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,则可能会将其提升到更大的大小。它们通常变为有符号,但如果任一操作数的类型范围大于int,则仍保持无符号状态。

有很多东西专门定义了转换是如何执行的,并编码了哪种类型的规则比其他类型“更高”(更大),然后我们在6.3.1.8中得到了真正的内容:通常的算术转换:

许多期望算术类型操作数的操作符会以类似的方式导致转换和生成结果类型。其目的是为操作数和结果确定一个公共的实类型。对于指定的操作数,每个操作数在不改变类型域的情况下转换为相应的实类型为公共实类型的类型。除非另有明确说明,否则公共实类型也是结果的相应实类型,如果操作数相同,则其类型域是操作数的类型域,否则则是复杂的。这种模式称为通常的算术转换:

..。一些关于浮动的东西..。

否则,整数提升将在两个操作数上执行。然后,将下列规则应用于提升操作数: 如果两个操作数都具有相同的类型,则不需要进一步的转换。否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则具有较小整数转换秩类型的操作数将转换为级别较大的操作数类型。否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则带符号整数类型的操作数转换为无符号整数类型的操作数类型。 否则,如果带符号整数类型的操作数的类型可以用无符号整数类型表示操作数类型的所有值,则具有无符号整数类型的操作数转换为带符号整数类型的操作数类型。 否则,两个操作数都转换为与带符号整数类型的操作数类型对应的无符号整数类型。

int8_t偶数= 0xBB;

0xBB形式为int (0x000000BB)类型的常数,然后截断为int8_t。

int16_t 2次=偶数<< 8;

偶数is符号从int8_t扩展到int,变为0xFFFFFFBB (假设机器上的int是32位)8的值是以类型int (这些类型匹配)形式形成的,因此不再执行进一步的转换操作(既然类型匹配了),得到0xFFFFFFFFFBB00,这个值被截断以适应int16_t,从而产生0xBB00。

2次=2次+偶数;

2的值从int16_t扩展到int,产生0xFFFFFFBB00 (-17664)偶数的符号从int8_t扩展到int,产生0xFFFFFFBB (-69)这些值被加起来,产生0xFFFFFFBABB (-17733),这个值被截断以适合于int16_t,产生0xBABB。

当我将两个都是0xFF的8位ints相加时,会发生什么?

它们都是扩展到int,产生0xFFFFFFFF,然后添加收益0xFFFFFFFE。这可能会被截断,也可能不会被截断,这取决于您存储它的位置。

当然,编译器可以自由地注意到,由于没有保存输出位,所以大部分扩展/截断操作都是毫无价值的工作,并对其进行优化。但结果必须是“好像”做了很长一段路的事情。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23134958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档