重拾 C/C++ 第一部分 变量与常量 总结与延伸

   本文章为摘抄与总结,能力有限,有错误与漏洞希望大佬们给予提示或帮助,因为引用了大规模的 C primer plus 内容,出发点为整理资料以供学习参考,如有侵权行为,联系必删.

   

重拾 C/C++ 第一部分

    • 一、数据存储单位
    • 二、字长
    • 三、变量类型几种特征 及其扩展
    • 四、数的进制表示
    • 五、全局(局部)与静态变量
    • 六、限定符的使用


一、数据存储单位

   1、什么是位?
         所谓位,是最基本的概念,在计算机中,由于只有逻辑0和逻辑1的存在,因此很多东西、动作、数字都要表示为一串二进制的字码例如: 1001 0000 1101等等。其中每一个逻辑0或者1便是一个位。例如这个例子里的1000 1110共有八个位,它的英文名字叫(bit),是计算机中最基本的单位

   2、什么是字节?
         所谓的字节 Byte,是由八个位组成的一个单元,也就是8个bit组成1个Byte。字节有什么用呢? 在计算机科学中,用于表示ASCII字符,便是运用字节来记录表示字母和一些符号~例如字符A便用 “0100 0001”来表示

   3、什么是字?
         而字节以上,便是字:16个位为一个字,它代表计算机处理指令或数据的二进制数位数,是计算机进行数据存储和数据处理的运算的单位。通常称16位是一个字,而32位呢,则是一个双字,64位是两个双字

   4、关系:1 字 = 2 字节 = 16 位
   5、字符与字节对应关系
         常见的编码字符与字节的对应关系如下:

   ① ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。

   ② UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。

   ③ Unicode编码中,一个英文等于两个字节,一个中文(含繁体)等于两个字节。
符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。

   ④ GBK编码方式是中文占两个字节,英文占1个字节。
   


二、字长

   在同一时间中处理二进制数的位数叫字长。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位(4字节)的二进制数据。二进制的每一个0或1是组成二进制的最小单位,称为位(bit)。常用的字长为8位、16位、32位和64位。字长为8位的编码称为字节,是计算机中的基本编码单位

转载 原文链接:https://blog.csdn.net/qq_38351824/article/details/104187098


三、变量类型几种特征 及其扩展

   首先是常见变量的几种简单特征归纳(64位处理器与编译器)
重拾 C/C++ 第一部分 变量与常量 总结与延伸_第1张图片
在这里要注意的点:
1、在程序中要注意变量的生存周期(全局,局部)与取值范围,否则会出现预期外的问题
2、在不同的位宽下,作为指针变量会存储首地址,占用字节相同
3、字符举例部分,常见情况为利用printf打印变量所用字符

转义序列汇总
转义字符赋给字符常量并打印出来会有对应的效果

转义序列 Value
\a 警报(ANSI C)
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 反斜杠(\)
\’ 单引号
\” 双引号
\ ? 问号
\ 0OO 八进制值(OO为有效的八进制数 0-7之中)
\ xhh 十六进制值 (hh为有效的十六进制数 0-f之中)

四、数的进制表示

   一个数字默认就是十进制的,表示一个十进制数字不需要任何特殊的格式。但是,表示一个二进制、八进制或者十六进制数字就不一样了,为了和十进制数字区分开来,必须采用某种特殊的写法,具体来说,就是在数字前面加上特定的字符,也就是加前缀
   1、二进制
   二进制由 0 和 1 两个数字组成,使用时必须以0b或0B(不区分大小写)开头,例如:

//合法的二进制
int a = 0b101;  //换算成十进制为 5
int b = -0b110010;  //换算成十进制为 -50
int c = 0B100001;  //换算成十进制为 33
//非法的二进制
int m = 101010;  //无前缀 0B,相当于十进制
int n = 0B410;  //4不是有效的二进制数字

   读者请注意,标准的C语言并不支持上面的二进制写法,只是有些编译器自己进行了扩展,才支持二进制数字。换句话说,并不是所有的编译器都支持二进制数字,只有一部分编译器支持,并且跟编译器的版本有关系。

   下面是实际测试的结果:
   Visual C++ 6.0 不支持。
   Visual Studio 2015 支持,但是 Visual Studio 2010 不支持;可以认为,高版本的 Visual Studio 支持二   进制数字,低版本的 Visual Studio 不支持。
   GCC 4.8.2 支持,但是 GCC 3.4.5 不支持;可以认为,高版本的 GCC 支持二进制数字,低版本的 GCC 不支持。
   LLVM/Clang 支持(内嵌于 Mac OS 下的 Xcode 中)。

   2、八进制
   八进制由 0~7 八个数字组成,使用时必须以0开头(注意是数字 0,不是字母 o),例如:

//合法的八进制数
int a = 015;  //换算成十进制为 13
int b = -0101;  //换算成十进制为 -65
int c = 0177777;  //换算成十进制为 65535
//非法的八进制
int m = 256;  //无前缀 0,相当于十进制
int n = 03A2;  //A不是有效的八进制数字

   3、十六进制
   十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,使用时必须以0x或0X(不区分大小写)开头,例如:

//合法的十六进制
int a = 0X2A;  //换算成十进制为 42
int b = -0XA0;  //换算成十进制为 -160
int c = 0xffff;  //换算成十进制为 65535
//非法的十六进制
int m = 5A;  //没有前缀 0X,是一个无效数字
int n = 0X3H;  //H不是有效的十六进制数字

   4、十进制
   十进制由 0~9 十个数字组成,没有任何前缀,和我们平时的书写格式一样,不再赘述。
   二进制数、八进制数和十六进制数的输出
   C语言中常用的整数有 short、int 和 long 三种类型,通过 printf 函数,可以将它们以八进制、十进制和十六进制的形式输出。上面的表格里以列举十进制输出的格式控制符,这里列举如何以八进制和十六进制的形式输出,下表列出了不同类型的整数、以不同进制的形式输出时对应的格式控制符:

short int long
八进制 %ho %o %lo
十进制 %hd %d %ld
十六进制 %hx 或者 %hX %x 或者 %X %lx 或者 %lX

   十六进制数字的表示用到了英文字母,有大小写之分,要在格式控制符中体现出来:
   %hx、%x 和 %lx 中的x小写,表明以小写字母的形式输出十六进制数;
   %hX、%X 和 %lX 中的X大写,表明以大写字母的形式输出十六进制数。

   八进制数字和十进制数字不区分大小写,所以格式控制符都用小写形式。如果你比较叛逆,想使用大写形式,那么行为是未定义的,请你慎重:
   有些编译器支持大写形式,只不过行为和小写形式一样;
   有些编译器不支持大写形式,可能会报错,也可能会导致奇怪的输出。

   注意,虽然部分编译器支持二进制数字的表示,但是却不能使用 printf 函数输出二进制,这一点比较遗憾。当然,通过转换函数可以将其它进制数字转换成二进制数字,并以字符串的形式存储,然后在 printf 函数中使用%s输出即可。考虑到读者的基础还不够,这里就先不讲这种方法了。

【实例】以不同进制的形式输出整数:

#include 
int main()
{
    short a = 0b1010110;  //二进制数字
    int b = 02713;  //八进制数字
    long c = 0X1DAB83;  //十六进制数字
   
    printf("a=%ho, b=%o, c=%lo\n", a, b, c);  //以八进制形似输出
    printf("a=%hd, b=%d, c=%ld\n", a, b, c);  //以十进制形式输出
    printf("a=%hx, b=%x, c=%lx\n", a, b, c);  //以十六进制形式输出(字母小写)
    printf("a=%hX, b=%X, c=%lX\n", a, b, c);  //以十六进制形式输出(字母大写)
    return 0;
}

`运行结果:
a=126, b=2713, c=7325603
a=86, b=1483, c=1944451
a=56, b=5cb, c=1dab83
a=56, b=5CB, c=1DAB83

   从这个例子可以发现,一个数字不管以何种进制来表示,都能够以任意进制的形式输出。数字在内存中始终以二进制的形式存储,其它进制的数字在存储前都必须转换为二进制形式;同理,一个数字在输出时要进行逆向的转换,也就是从二进制转换为其他进制。
   输出时加上前缀
   请读者注意观察上面的例子,会发现有一点不完美,如果只看输出结果:
   对于八进制数字,它没法和十进制、十六进制区分,因为八进制、十进制和十六进制都包含 0~7 这几个数字。
   对于十进制数字,它没法和十六进制区分,因为十六进制也包含 0~9 这几个数字。如果十进制数字中还不包含 8 和 9,那么也不能和八进制区分了。
   对于十六进制数字,如果没有包含 a~f 或者 A~F,那么就无法和十进制区分,如果还不包含 8 和 9,那么也不能和八进制区分了。

   区分不同进制数字的一个简单办法就是,在输出时带上特定的前缀。在格式控制符中加上#即可输出前缀,例如 %#x、%#o、%#lX、%#ho 等,请看下面的代码:

#include 
int main()
{
    short a = 0b1010110;  //二进制数字
    int b = 02713;  //八进制数字
    long c = 0X1DAB83;  //十六进制数字
   
    printf("a=%#ho, b=%#o, c=%#lo\n", a, b, c);  //以八进制形似输出
    printf("a=%hd, b=%d, c=%ld\n", a, b, c);  //以十进制形式输出
    printf("a=%#hx, b=%#x, c=%#lx\n", a, b, c);  //以十六进制形式输出(字母小写)
    printf("a=%#hX, b=%#X, c=%#lX\n", a, b, c);  //以十六进制形式输出(字母大写)
   
    return 0;
}

   运行结果:
   a=0126, b=02713, c=07325603
   a=86, b=1483, c=1944451
   a=0x56, b=0x5cb, c=0x1dab83
   a=0X56, b=0X5CB, c=0X1DAB83

   十进制数字没有前缀,所以不用加#。如果你加上了,那么它的行为是未定义的,有的编译器支持十进制加#,只不过输出结果和没有加#一样,有的编译器不支持加#,可能会报错,也可能会导致奇怪的输出;但是,大部分编译器都能正常输出,不至于当成一种错误。

原文链接http://c.biancheng.net/view/1759.html


五、全局(局部)与静态变量

   普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。

普通局部变量存储于进程栈空间,使用完毕会立即释放。

静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。

    变量在全局数据区分配内存空间;编译器自动对其初始化,其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。

普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。


六、限定符的使用

   const 常量
    当在类型名前面加上关键字 const 后,表示它是一个只读的量。这种变量不能修改它的值
因而称为常量,const会限定变量的权限,变成只读(不能做左值)。左值:写权限 右值:读权限
可以保护变量,不被随意更改。
   1.基本数据类型对于const透明。
   2.const修饰它的直接右边。
    const int*p=&a;=>int const *p1=&a;
    *p1=1000;//出错,*p1不能做左值
   3.权限可以同等或者缩小传递,但不能放大传递。
   volatil限定符
   一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

  1. 并行设备的硬件寄存器(如:状态寄存器
  2. 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
  3. 多线程应用中被几个任务共享的变量

   restrict限定符

   C语言中的一种类型限定符,用于告诉编译器,对象已经被指针所引用,不能通过除去该指针以外的所有其他直接或间接的方式修改该对象的内容

   restrict限定符的用法
restrict关键字允许编译器优化某部分代码以更好地支持计算。它只能用于指针,表明该指针是访问该对象唯一且初始的方式。要弄明白为什么这样做有用,先看几个例子。考虑下面的代码:

   int ar[10];
   int * restrict restar= (int *) malloc(10 * sizeof(int));
   int * par= ar;

   这里,指针restar是访问由malloc()所分配的内存的唯一且初始的方式。因此,可以用restrict关键字限定它。而指针par既不是访问ar数组中数据的初始方式,也不是唯一方式。所以不用把它设置成restrict。

   restrict关键字有两个读者。一个是编译器,该关键字告诉编译器可以自由假定一些优化方案。另一个读者是用户,该关键字告知用户要使用满足restrict要求的参数,总而言之,编译器不会检查用户是否遵循这一限制,但是无是它可能产生严重后果。

restrict限定符原文链接https://blog.csdn.net/nbadwde/article/details/80703781

此版为最初总结格式,后续可能会更改

你可能感兴趣的:(重拾 C/C++ 第一部分 变量与常量 总结与延伸)