C++ 无符号和有符号int和printf
我知道我正在给signed int分配一个大于它所能处理的值。另外,我应该使用C++ 无符号和有符号int和printf,c++,c,C++,C,我知道我正在给signed int分配一个大于它所能处理的值。另外,我应该使用%d表示已签名,使用%u表示未签名。类似地,我不应该将-ve值赋给unsigned。但如果我做了这样的作业并使用如下printf,我会得到如下结果 我的理解是,在每种情况下,数字转换为其2的互补二进制表示,这与-1或4294967295相同。这就是为什么%u通过忽略-ve最左边的位来为签名打印4294967295。当将%d用于有符号整数时,它使用最左边的位作为-ve标志并打印-1。类似地,unsigned的%u会打印u
%d
表示已签名,使用%u
表示未签名。类似地,我不应该将-ve
值赋给unsigned。但如果我做了这样的作业并使用如下printf,我会得到如下结果
我的理解是,在每种情况下,数字转换为其2的互补二进制表示,这与-1
或4294967295
相同。这就是为什么%u
通过忽略-ve
最左边的位来为签名打印4294967295
。当将%d用于有符号整数时,它使用最左边的位作为-ve
标志并打印-1
。类似地,unsigned的%u
会打印unsigned值,但%d
会将数字视为有符号,从而打印-1
。对吗
signed int si = 4294967295;
unsigned int ui = 4294967295;
printf("si = u=%u d=%d\n", si, si);
printf("ui = u=%u d=%d\n", ui, ui);
输出:
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
输出:
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
这里发生了一些事情,让我们首先说,使用不正确的格式说明符来
printf
是未定义的行为,这意味着程序的结果是不可预测的,实际发生的情况将取决于许多因素,包括编译器、体系结构、优化级别等
对于由相应的标准定义的符号/非符号转换,C和C++都实现了实现定义的行为,以转换大于符号整数类型的值,从C++草稿标准:
如果目标类型是有符号的,则如果可以在目标类型(和)中表示该值,则该值将保持不变 位域宽度);否则,该值由实现定义 例如,gcc
选择使用相同的:
对于转换为宽度为N的类型,该值以2^N的模减小,以在该类型的范围内;没有发出任何信号
当你将代码> -1 < /C> >在C和C++中的无符号值时,结果将始终是该类型的最大未签名值,从草案C++标准:
如果目标类型为无符号,则结果值最小 与源整数全等的无符号整数(模2n,其中n为 用于表示无符号类型的位数)。[注:在 二的补语表示法,这种转换是概念上的和逻辑上的 位模式没有变化(如果没有截断)。 -[完注] C99中的措辞更容易理解: 否则,如果新类型是无符号的,则该值将由 重复地加上或减去一个大于最大值 可以在新类型中表示,直到值在 新型的 因此,我们有以下几点:-1 + (UNSIGNED_MAX + 1)
其结果是UNSIGNED_MAX
至于printf
和不正确的格式说明符,我们可以从C99标准草案的7.19.6.1
部分看到,fprintf函数说明:
如果转换规范无效,则行为无效
未定义。248)如果任何参数不是
对应的转换规范,行为未定义
<>代码> fPrtutf关于格式说明符覆盖<代码> PROTFF < /C> > C++中关于<代码> Prtff>的下落。
这就是为什么在4294967295签名打印时忽略-ve最左端位的原因。当将%d用于有符号整数时,它使用最左边的位作为-ve标志并打印-1
在无符号情况下,“最左边”或最高有效位不被忽略,且不为负;相反,它的位置值为231
在负的情况下,符号位不是标志;相反,它是一个位置值为-231的位
在这两种情况下,整数的值等于设置为1的所有二进制数字(位)的位值之和
以这种方式对有符号值进行编码称为。它不是唯一可能的编码方式;例如,你所描述的是符号和大小,一个人的补语是另一种可能性。然而,在实践中很少遇到这些替代编码,这不仅是因为二者的互补性是算术在现代硬件上的工作原理,但可能是最神秘的架构。请注意,我对这个问题的回答解释了。。。因此,将
-1
赋值给无符号值始终是定义良好的行为。但仅仅将负整数值重新解释为无符号的
整数值并不是定义良好的。正如将太大的无符号
整数值重新解释为有符号
整数值一样,您可能会发现“std::numeric_limits”很有用。从uin32_t更改为uint64_t更具可读性。std::numeric_limits::max(),变为std::numeric_limits::max()等等。@Deduplicator你是说在printf
的上下文中?@Deduplicator我在printf
上下文中添加了使其成为UB的引号,并且无论在优化下转换是否会做坏事,编译器都可以用UB做任何事情。不要忘记变量函数的措辞,也就是说,传递的是signed
还是unsigned
整数类型的值并不重要,只要该值在这两种类型中都是可表示的。我发现,通过查看这种情况的1字节等效值,可以更容易地将其可视化。设置8位时,作为无符号位模式,其值通常为255。作为2s补码有符号值,底部7位的值为127,但顶部位的值为-128,产生的有符号值为-1。类似的情况也发生在2、4和8字节的值上:所有1位模式的值为-1作为有符号整数。只是更容易勾勒出并掌握8位的位模式…@Razzle肯定更容易,但这不是问题所在。如果你觉得自己的答案增加了价值(很可能是这样),请随意发布。