繁体   English   中英

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。 或更高。

单个3int类型的 integer 文字。

您可以使用sizeof运算符检查它。 它会给你以字节为单位的参数大小。 只需尝试获取inta3的大小。

#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类型的 object 的大小是实现定义的 该标准仅要求INT_MAX不得小于+32767 ,即2 ^ 15 - 1

如果在您的系统中, int类型的 object 的大小等于 4,那么像3这样的 integer 常量将占用一个等于4个字节的 memory 块。

请注意,例如字符 integer 常量也具有int类型。

所以在这两个声明中

char a = 3;

char a = '\3';

如果sizeof( int )等于4 ,则具有int类型的常量3'\3'占用4个字节。

3被称为integer 常量,它的类型很像任何命名变量。 如果键入的数字可以放入int int 否则,如果它不适合,编译器会尝试将它放入一个long中,然后是long long

有各种相当复杂的规则来说明如何做到这一点,我不会在这里提及所有肮脏的细节——对此感兴趣的人可以查看 C 标准 6.4.4.1 中的表格。 对于普通程序员来说,知道我们还可以通过添加U后缀来强制 integer 常量无符号或通过添加L后缀强制它变long可能就足够了。 3U3L或组合3UL (小写的ul也可以。)

在现实世界的计算机上, 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
}

https://godbolt.org/z/3675zv

问题“3 代表多少位?” 实际上很棘手。 如果我们能找到3,那么我们就可以回答它。 所以问题是: 3 在哪里

真正发生的是:

int a = 3;

是相同的:

int a;
a = 3;

编译器确保变量a将有 4 个字节的空间(它在编译时执行此操作),然后它还会在程序中放置一条指令,当您运行程序时将数字 3 存储在该空间中。

我们可以使用这个有用的在线工具来编译程序并查看编译器实际输出的汇编/机器代码: 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 这是什么类型的指令(“在堆栈帧中的特定 position 中放入特定数字”)。 fc是堆栈帧中的 position。 03 00 00 00是它放在那里的特定数字(以小端格式)。 这是源代码中的数字 3。 所以在这种情况下,它占用了 4 个字节。


请注意,它并不总是相同的。 如果我们为 ARM CPU 而不是 x86-64 编译,那么这些是相关指令

mov r3, #3
str r3, [fp, #-8]

不幸的是,godbolt 不会向我们显示机器代码,但我们可以在 ARM 手册中查找 MOV # 指令,该指令告诉我们该指令长 4 个字节,而被移动的数字仅占用其中 2 个字节。 如果您使用的数字不适合 2 个字节,则其他位自动为零。 显然它使用了不同的指令。

通常我们不会谈论指令的大小,因为它们的变化比数据大小要大得多。 int a; 总是保留 4 个字节(如果您的系统的int是 4 个字节),但是将特定位放入该空间的指令可以具有不同的大小。


即使在 x86-64 上,数字也可以占用不同数量的空间。 如果我确实return 0; ,编译器将其转换为xor eax, eax ( 31 c0 )。 该指令中根本没有数字0 31 c0是所有类型的指令,没有数据)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM