我有一个简单的程序。 请注意,我使用的是无符号固定宽度整数1个字节。
#include <cstdint>
#include <iostream>
#include <limits>
int main()
{
uint8_t x = 12;
std::cout << (x << 1) << '\n';
std::cout << ~x;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
return 0;
}
我的输出如下。
24
-13
我测试了更大的数字,运算符<<
总是给我正数,而运算符~
总是给我负数。然后我使用了sizeof()
并找到了......
当我使用左移位运算符(
<<
)时,我收到一个无符号的4字节整数。当我使用按位非运算符(
~
)时,我收到一个带符号的4字节整数。
似乎按位非运算符(~
)执行有符号整数提升,就像算术运算符一样。但是,左移运算符(<<
)似乎会提升为无符号积分。
我觉得有必要知道编译器什么时候改变我背后的东西。如果我在分析中是正确的,那么所有按位运算符都会提升为4字节整数吗?为什么一些签名和一些未签名?我很困惑!
编辑:我总是得到肯定或总是得到负值的假设是错误的。但由于错误,我理解真正发生的事情,这要归功于下面的重要答案。
答案 0 :(得分:8)
[expr.unary.op]
~
的操作数应具有整数或无范围的枚举类型;该 结果是其操作数的补码。 整体促销活动 进行。强>
[expr.shift]
班次运营商
<<
和>>
从左到右分组。 [...]操作数应为整数或无范围的枚举类型,并且执行整体促销。
uint8_t
(通常会在幕后unsigned_char
)的整体推广是什么?
[conv.prom]
除
bool
,char16_t
,char32_t
以外的整数类型的prvalue,或者wchar_t
,其整数转换等级(4.13)小于等级 如果int
可以代表所有int
,则int
可以转换为unsigned int
类型的prvalue 源类型的值;否则,源prvalue可以 转换为int
类型的prvalue。
所以uint8_t
,因为int
的所有值都可以由int(12) << 1
表示。
什么是int(24)
? ~int(12)
。
什么是int(-13)
? {{1}}。
答案 1 :(得分:5)
出于性能原因,C和C ++语言认为int
是最自然的&#34;整数类型,而不是&#34;较小的#34;比int
被认为是&#34;存储&#34;类型。
在表达式中使用存储类型时,它会自动转换为int
或unsigned int
。例如:
// Assume a char is 8 bit
unsigned char x = 255;
unsigned char one = 1;
int y = x + one; // result will be 256 (too large for a byte!)
++x; // x is now 0
发生的事情是第一个表达式中的x
和one
已被隐式转换为整数,已计算加法并将结果存储回整数。换句话说,没有使用两个无符号字符进行计算。
同样,如果表达式中有float
值,编译器要做的第一件事就是将其提升为double
(换句话说,float
是存储类型而double
1}}是浮点数的自然大小)。这就是为什么如果你使用printf
来打印浮动广告,你不需要在格式字符串中说%lf
并且%f
就足够了(%lf
是scanf
需要,因为该功能存储结果,而float
可能小于double
。
C ++使问题变得复杂,因为在将参数传递给函数时,您可以区分int
和更小的类型。因此,在每个表达式中执行转换并不总是如此...例如,您可以拥有:
void foo(unsigned char x);
void foo(int x);
,其中
unsigned char x = 255, one = 1;
foo(x); // Calls foo(unsigned char), no promotion
foo(x + one); // Calls foo(int), promotion of both x and one to int
答案 2 :(得分:4)
我测试了更大的数字和运算符&lt;&lt;总是给我积极的 数字,而操作员〜总是给我负数。然后我 使用了sizeof()并找到了......
错了,测试一下:
uint8_t v = 1;
for (int i=0; i<32; i++) cout << (v<<i) << endl;
给出:
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
-2147483648
uint8_t
是一个8位长的无符号整数类型,它可以表示[0,255]范围内的值,因为它包含在int
范围内的范围被提升为{{1} (不是int
)。促销unsigned int
优先于促销int
。
答案 3 :(得分:3)
查看two's complement以及计算机如何存储负整数 试试这个
#include <cstdint>
#include <iostream>
#include <limits>
int main()
{
uint8_t x = 1;
int shiftby=0;
shiftby=8*sizeof(int)-1;
std::cout << (x << shiftby) << '\n'; // or std::cout << (x << 31) << '\n';
std::cout << ~x;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
return 0;
}
输出为-2147483648
通常,如果有符号数的第一位为1,则认为是负数。当你拿大量并转移它。如果你移动它使第一位为1则为负
**编辑**
好吧,我可以想到为什么移位运算符会使用unsigned int。考虑右移操作>>
如果你右移-12你会得到 122 而不是-6。这是因为它在开头添加零而不考虑符号