第一个C语言程序
与hello world不同,这里是另外一个简单的C语言程序。接下来对这个程序结构进行简要介绍,使得了解C程序的基本架构。#include <stdio.h>
这一行的意思是引入一个头文件,.h就是head的意思。一般地,在C语言或C++中,会把用来#include的文件的扩展名叫 .h,称其为头文件。 #include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体代码尺寸;或者提供跨工程公共代码。
stdio 就是指 “standard input & output"(标准输入输出)
所以,源代码中如用到标准输入输出函数时,就要包含这个头文件
也可以自己写一个.h或者.cpp文件,在其中存储一些自己写的函数,放在程序的同一文件夹下,这时也就可以include自己的文件调用自己写的函数了。int main()
printf()
本程序包含两个函数。函数就是C语言中的程序模块,当我们经常要执行一项任务时,就可以抽象出一个函数实现这个功能。函数在使用前必须声明,一般用函数原型的方法实现,这里不在赘述。
函数一般的形式:return_value_type function_name(parameter_list)
即 返回值 函数名(形参列表)
int main()中,返回值就是int整型,而且main()函数是一个C程序的唯一入口。
所以,上图的代码其实是不规范的,应该在末尾加上return 0;表明main()的返回值。
那既然程序都结束了,返回这个0干什么呢?其实这个return 很多时候都是用来检测函数是否正确执行的,当函数正确执行完成,就会返回0,如果异常或者退出,就会返回随机值。
main()中没有形参,但是printf()中可以看到有多个参数,%d表示的是10进制有符号格式化输出后续值。sizeof(a)表示求变量a的所占字节数。除了%d,C语言还有多种格式化输出符号,这里也暂时不在展开。\n则是回车的转义。
程序得到的结果是4。代表a占据4个字节。
到这里,其实对C的基本语法介绍了不少了。现在可以聊聊更有趣的事情,C既然是相比偏底层的高级语言,也可以据此了解一下计算机的数字存储。
首先说明,计算机中1字节(byte)= 8比特(位,bit)
这里我们选择的是64位TDM-GCC,按常理,int应该是64位,但是这里编译器是结果确实32位。因为有一个直接制定64位的 int64, 所以为了兼容之前的代码, 很多64编译器int仍然是4字节32bit.
32bit,其实表示a有32位存放0和1,那是不是a最大是2^32-1=4 294 967 296-1呢,我们看一看.
并不是,相反,结果是负数,其实现在a早就已经发生了溢出
这里就引出了计算机&数逻中几种简单的编码:源码,反码,补码。
为了表示正负,原码编码提供了一种方式,让二进制数字的"最高位"表示符号,0正1负,后续位做数值位。如0111表示7,1110表示-6.但是这种方式有一个问题就是1000和0000都表示0,就有了正0负0之说。而且在计算机中,用源码计算也不方便(感兴趣可参考P&H或者CSAPP)。
反码是原码的补充,也是0正1负,但是不同处在于,当数字是负数时,反码是原码的除符号位位外按位求反。比如7原码0111,反码0111,-6的原码1110,反码却是1001.
最后一种,也是最重要的,叫做补码(two’s complement).这里对补码进行一个通俗的解释,补码是一个位有"两种"情况的编码,最高位是负位,其余位是正位。补码0111表示7,1111表示-8+7=-1,1000表示-8。补码的一个很重要的作用就是把减法运算化为加法运算,而且可以看到,4位补码表示范围是-8~+7,没有重复(正0负0).
比如5-3,补码可表示为5+(-3)
0101
1101 add
= 0 0 1 0 (2)
4位编码,丢弃溢出位1。
这样可以大大简化计算机设计。所以,计算机中通常默认存储为补码。
补码还有一个特点,那就是位数扩展非常方便,如4位补码1001,扩展成8位就是1111 1001
三者之间有简单的转换规则,这里也不再赘述。
现在我们可以解释之前的结果了a用补码表示,最大只支持2^31-1=2 147 483 648-1.
测试试一试
我们知道了2 147 483 647=0111…1(31个1)那如果令a=2 147 483 648呢?我们猜测一下。
2 147 483 647+1=0111…1+000…1=100…000,根据补码编码,这个数字是多少?答案是-2^31=-2 147 483 648.我们验证一下
完美符合我们的预测。
此时,程序已经发生了溢出,a既然是32位,向高位的进位会被舍弃,只会读取0-31位。如果我们继续扩大数字,我们依然可以根据规则预测溢出后的结果。
2 147 483 647+1=100…0000
继续+1=100…001,所以,2 147 483 649溢出结果应该是100…0001,按照补码,应该为-2 147 483 647
如果我们不想用补码表示,我们只要表示正数,又不想浪费空间,怎么办?C也有办法,那就是把a令为无符号数(unsigned int)
此时,a没有符号位,0000表示0,1111表示15.
所以a最大可表示2^32-1=4 294 967 296-1
除此之外,如果数字过大,C还可以用long/ long前缀扩大a占据的内存大小
b占据了8个字节,达到了64bit,可表示数值范围大大扩大。
这就是C为什么能够带给学习者对计算机相比更深刻的认识的一格例子,这也体现了C语言的魅力
来源:CSDN
作者:Waldenth
链接:https://blog.csdn.net/Waldenth/article/details/104033224