C编程中位数的问题
Question in number of bits in C programming
如果我这样做
int a = 3,则3用32位二进制表示
如果我这样做
char a = 3,则3用8位二进制表示
我的问题是在使用值进行初始化之前,3 代表了多少位?
(也就是说等号右边的“3”有多少位)
很常见 int
有 32 位,但不能保证。它也可以是 16 或 64。或更高。
单个 3
是 int
.
类型的整数文字
您可以使用 sizeof
运算符进行检查。它会给你参数的大小(以字节为单位)。只需尝试获取 int
、a
和 3
.
的大小
#include <stdio.h>
int main()
{
int a = 3;
printf("%ld\n", sizeof(a)); // gives 4 bytes (32 bit) on my PC
printf("%ld\n", sizeof(int)); // gives 4 bytes (32 bit) on my PC
printf("%ld\n", sizeof(3)); // gives 4 bytes (32 bit) on my PC
return 0;
}
此外,3
的类型为 int
。所以它的大小等于 int
.
的大小
int
类型的对象的大小是实现定义的标准仅要求 INT_MAX
不得小于 +32767
即 2 ^ 15 - 1
如果在您的系统中 int
类型的对象的大小等于 4,那么像 3
这样的整数常量将占用等于 4
字节的内存块.
注意,例如字符整型常量也是int
.
类型
所以在这两个声明中
char a = 3;
和
char a = '';
如果 sizeof( int )
等于 4
,int
类型的常量 3
和 ''
占用 4
个字节。
3
称为 整数常量,它的类型与任何命名变量非常相似。如果键入的数字可以放在 int
中,则它总是键入 int
。否则,如果放不下,编译器会尝试将其放入 long
,然后 long long
.
关于如何做到这一点有各种相当复杂的规则,我不会在这里提及所有肮脏的细节 - 对此感兴趣的人可以查看 C 标准 6.4.4.1 中的表格。对于普通程序员来说,知道我们还可以通过添加 U
后缀强制整数常量无符号或通过添加 L
后缀强制其为 long
可能就足够了。即 3U
或 3L
或组合 3UL
。 (小写 u
和 l
也适用。)
在实际计算机上,int
总是 2 或 4 个字节大。 long
是 4 或 8 个字节大。来自具有 4 字节 int
和 8 字节 long
的 64 位 Linux 计算机的示例:
#include <stdio.h>
int main (void)
{
printf("%zu\n", sizeof(int)); // 4
printf("%zu\n", sizeof(3)); // 4
printf("%zu\n", sizeof(3L)); // 8
printf("%zu\n", sizeof(2147483647)); // 4, fits int
printf("%zu\n", sizeof(2147483648)); // 8, doesnt fit
}
问题“3 用多少位来表示?”实际上很棘手。如果我们能找到 3,那么我们就可以回答它。所以问题是:3在哪里?
真正发生的是:
int a = 3;
等同于:
int a;
a = 3;
编译器确保变量 a
有 4 个字节的 space(它在编译时执行此操作),然后它还在程序中放入一条指令来存储当你 运行 程序时 space 中的第 3 号。
我们可以使用这个有用的在线工具编译程序,看看编译器实际输出的 assembly/machine 代码是什么:https://godbolt.org/z/a9Pohn
在这种情况下,我输入了程序:
int main() {
int a;
a = 3;
}
并使用“x86-64 gcc 10.2”编译,没有优化。这是编译后的代码(汇编代码和机器代码):
main:
55 push rbp
48 89 e5 mov rbp,rsp
c7 45 fc 03 00 00 00 mov DWORD PTR [rbp-0x4],0x3
b8 00 00 00 00 mov eax,0x0
5d pop rbp
c3 ret
如果我们可以阅读汇编,我们可以看到编译器选择插入到程序中以初始化变量 a
的指令是 mov DWORD PTR [rbp-0x4],0x3
。在机器代码中,它被写成 c7 45 fc 03 00 00 00
。指令是数字3的来源。
指令长度为 7 个字节。 c7 45
告诉 CPU 这是什么类型的指令(“将特定数字放在堆栈帧中的特定位置”)。 fc
是堆栈帧中的位置。 03 00 00 00
是它放在那里的具体数字(小端格式)。这是源代码中的数字 3。所以在这种情况下,它占用了4个字节。
请注意,它并不总是相同的。如果我们为 ARM CPU 而不是 x86-64 编译,那么这些是相关的说明
mov r3, #3
str r3, [fp, #-8]
不幸的是,godbolt 不会向我们显示机器码,但是 we can look up the MOV # instruction in the ARM manual 告诉我们指令有 4 个字节长,被移动的数字只占用其中的 2 个字节!其他位自动为零。如果您使用的数字不适合 2 个字节,显然它使用了不同的指令。
通常我们不讨论指令的大小,因为它们的变化比数据大小大得多。 int a;
总是保留 4 个字节(如果您的系统 int
是 4 个字节)但是将特定位放入 space 的指令可以有不同的大小。
即使在 x86-64 上,数字也会占用不同数量的 space。如果我执行 return 0;
,编译器会将其转换为 xor eax, eax
(31 c0
)。该指令中根本没有数字 0
! (31 c0
是所有类型的指令,没有数据)
如果我这样做
int a = 3,则3用32位二进制表示
如果我这样做
char a = 3,则3用8位二进制表示
我的问题是在使用值进行初始化之前,3 代表了多少位?
(也就是说等号右边的“3”有多少位)
很常见 int
有 32 位,但不能保证。它也可以是 16 或 64。或更高。
单个 3
是 int
.
您可以使用 sizeof
运算符进行检查。它会给你参数的大小(以字节为单位)。只需尝试获取 int
、a
和 3
.
#include <stdio.h>
int main()
{
int a = 3;
printf("%ld\n", sizeof(a)); // gives 4 bytes (32 bit) on my PC
printf("%ld\n", sizeof(int)); // gives 4 bytes (32 bit) on my PC
printf("%ld\n", sizeof(3)); // gives 4 bytes (32 bit) on my PC
return 0;
}
此外,3
的类型为 int
。所以它的大小等于 int
.
int
类型的对象的大小是实现定义的标准仅要求 INT_MAX
不得小于 +32767
即 2 ^ 15 - 1
如果在您的系统中 int
类型的对象的大小等于 4,那么像 3
这样的整数常量将占用等于 4
字节的内存块.
注意,例如字符整型常量也是int
.
所以在这两个声明中
char a = 3;
和
char a = '';
如果 sizeof( int )
等于 4
,int
类型的常量 3
和 ''
占用 4
个字节。
3
称为 整数常量,它的类型与任何命名变量非常相似。如果键入的数字可以放在 int
中,则它总是键入 int
。否则,如果放不下,编译器会尝试将其放入 long
,然后 long long
.
关于如何做到这一点有各种相当复杂的规则,我不会在这里提及所有肮脏的细节 - 对此感兴趣的人可以查看 C 标准 6.4.4.1 中的表格。对于普通程序员来说,知道我们还可以通过添加 U
后缀强制整数常量无符号或通过添加 L
后缀强制其为 long
可能就足够了。即 3U
或 3L
或组合 3UL
。 (小写 u
和 l
也适用。)
在实际计算机上,int
总是 2 或 4 个字节大。 long
是 4 或 8 个字节大。来自具有 4 字节 int
和 8 字节 long
的 64 位 Linux 计算机的示例:
#include <stdio.h>
int main (void)
{
printf("%zu\n", sizeof(int)); // 4
printf("%zu\n", sizeof(3)); // 4
printf("%zu\n", sizeof(3L)); // 8
printf("%zu\n", sizeof(2147483647)); // 4, fits int
printf("%zu\n", sizeof(2147483648)); // 8, doesnt fit
}
问题“3 用多少位来表示?”实际上很棘手。如果我们能找到 3,那么我们就可以回答它。所以问题是:3在哪里?
真正发生的是:
int a = 3;
等同于:
int a;
a = 3;
编译器确保变量 a
有 4 个字节的 space(它在编译时执行此操作),然后它还在程序中放入一条指令来存储当你 运行 程序时 space 中的第 3 号。
我们可以使用这个有用的在线工具编译程序,看看编译器实际输出的 assembly/machine 代码是什么:https://godbolt.org/z/a9Pohn
在这种情况下,我输入了程序:
int main() {
int a;
a = 3;
}
并使用“x86-64 gcc 10.2”编译,没有优化。这是编译后的代码(汇编代码和机器代码):
main:
55 push rbp
48 89 e5 mov rbp,rsp
c7 45 fc 03 00 00 00 mov DWORD PTR [rbp-0x4],0x3
b8 00 00 00 00 mov eax,0x0
5d pop rbp
c3 ret
如果我们可以阅读汇编,我们可以看到编译器选择插入到程序中以初始化变量 a
的指令是 mov DWORD PTR [rbp-0x4],0x3
。在机器代码中,它被写成 c7 45 fc 03 00 00 00
。指令是数字3的来源。
指令长度为 7 个字节。 c7 45
告诉 CPU 这是什么类型的指令(“将特定数字放在堆栈帧中的特定位置”)。 fc
是堆栈帧中的位置。 03 00 00 00
是它放在那里的具体数字(小端格式)。这是源代码中的数字 3。所以在这种情况下,它占用了4个字节。
请注意,它并不总是相同的。如果我们为 ARM CPU 而不是 x86-64 编译,那么这些是相关的说明
mov r3, #3
str r3, [fp, #-8]
不幸的是,godbolt 不会向我们显示机器码,但是 we can look up the MOV # instruction in the ARM manual 告诉我们指令有 4 个字节长,被移动的数字只占用其中的 2 个字节!其他位自动为零。如果您使用的数字不适合 2 个字节,显然它使用了不同的指令。
通常我们不讨论指令的大小,因为它们的变化比数据大小大得多。 int a;
总是保留 4 个字节(如果您的系统 int
是 4 个字节)但是将特定位放入 space 的指令可以有不同的大小。
即使在 x86-64 上,数字也会占用不同数量的 space。如果我执行 return 0;
,编译器会将其转换为 xor eax, eax
(31 c0
)。该指令中根本没有数字 0
! (31 c0
是所有类型的指令,没有数据)