C语言(关键字、语句及运算)

目录

一、关键字

1、register

2、static

3、const

4、volatile

5、extern

6、struct(结构体)

7、union(共用体)

return 0;}

8、enum

9、typedef

10、宏—#define

二、表达式及语句

1、选择语句(if)

2、循环语句(for while do ...while)

3、switch分支语句

4、goto语句

三、位运算

1、按位与──&

2、按位或──|

3、按位异或──^

4、按位取反──~

5、按位左移──<<

6、按位右移──>>

应用举例 [案例]

[案例] 从键盘上输入1个正整数给int变量num,按二进制位输出该数。

一、关键字
1、register
register:请求编译器尽可能地将变量存在CPU内部寄存器中;

使用注意: register修饰变量的类型必须是CPU所接受的;

register变量可能不是在内存中存储,所以不能使用&来获取变量的地址(内存中含有地址)

2、static
全局静态变量:作用范围局限于它的源文件,即只有本文件内的代码才可以访问它,变量名在其他文件内不可见

局部静态变量:局限于特定函数,但出作用域并不释放,在函数体内的静态变量的值也能够维持

静态函数:作用范围仅限于它的源文件,即只有本文件内才能够调用,函数名在其他文件不可见

存放位置(static):程序开始时,存放在全局数据区,程序结束时释放空间,默认初始化值是0,使用时可改变其值;

局部变量 ——静态局部变量(由栈区 到 全局数据区;默认值由 垃圾值 到 0;作用范围特定函数内(不变));

全局变量 ——静态全局变量(作用范围由 全部工程文件 到 当前文件;默认值为 0(不变);位置:全局数据区不变)

普通函数 ——静态函数(作用范围由 全部工程文件 到 当前文件)

函数不允许嵌套定义

举例:认真体会:

 

3、const
在面向对象语言当中(C++)中,const用于定义 常量;

在C语言中,const用来定义只读变量

strcpy( chsr *dest , const char *src) 指:源字符串(不可修改)复制到 (可改的目标文件中)

const int* a; int const *a;

是一个指向const int型的指针,a所指向的内存单元不可改写,所以(*a)++是不允许的,但a可以改写,所以a++是允许的。(若 int i;a = &i ; *a = 5(错误);所以不能通过*a 改变i 的值; 但是可以改变 i 的值;)

int* const a;

a是一个指向int型的const指针,*a是可以改写的,但a不允许改写。

int const * const a;

a是一个指向const int型的const指针,因此*a和a都不允许改写。

const给读代码的人传达非常有用的信息。比如一个函数的参数是const char *,你在调用这个函数时就可以放心地传给它char *或const char *指针,而不必担心指针所指的内存单元被改写。 尽可能多地使用const限定符,把不该变的都声明成只读,这样可以依靠编译器检查程序中的Bug,防止意外改写数据。

const对编译器优化是一个有用的提示,编译器也许会把const变量优化成常量

4、volatile

在寄存器定义(0x86);用volatile修饰,能较好的避免被优化掉;

 

5、extern
extern:表明变量或函数的定义在别的文件中,下面用到的这些变量或是函数是外来的,不是本文件定义的,提示编译器遇到此变量或函数时,在其他模块中寻找定义;

扩展使用范围:extern修饰变量的声明。举例来说,如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v。

如下图所示:

 

static 与 extern :static int a :静态全局变量 。如:下图所示:

 

加上static,限制了a的作用域,在file2.c中引用失败;但不管是否加上static(不加是全局变量),a都按静态存储方式(全局数据区)存放。

 

如果一个函数只能被本文件中其它函数所调用,称为内部函数(或静态函数)。定义时在函数类型前加static。(函数定义时,加与不加extern ,都是一样的)

6、struct(结构体)
多种数据组合起来的一个整体,其表现形式是一个结构体。

内存空间是分配给变量的,不分配给数据类型(不见变量,不分配)

结构体变量的内存空间是由内部各个变量所占空间之和

1、结构体创建(创建一个新的类型)

方法一:

struct node

{ char a;

short b;

char c;

}; (注意:;不能省)

struct nade link;(数据结构类型 定义变量(link))

 

struct student

{ int num;

char name[20];

float score;

}stu1, stu2; (等于:定义结构体类型 并且struct student stu1,stu2;)

 

方法二:

typedef struct

{ char a;

short b;

char c;

}node;

nade link;(数据结构类型 定义变量(link))

 

无名结构体定义:

struct { int num;

char name[20];

float score;

}stu1, stu2;(无名结构体类型 定义变量 stu1 ,stu2)

2、结构体的意义

结构体的花括弧内是该结构体中的各个成员,由它们组成一个结构体;在结构体内对各成员都应进行类型声明;

“成员表列”也称为域表。每个成员也称为结构体中的一个域,成员名命名规则与变量名一样;成员也可以是一个已定义的结构体类型变量:

 

成员也可以是指向本结构体类型的指针变量(结构体指针只能指向自己):

 

每个成员名前的类型标识符可以为已经定义了的任意类型,当然可以是结构体类型标识符,即结构体成员也可以是另一个结构体变量。

在程序中可以定义多个结构体类型,不同结构体类型用不同的结构体名来区分。

3、结构体的引用形式

结构体变量名. 成员名(“.”是成员运算符,在所有的运算符中优先级最高; ”.“一般变量用;—> 指向结构体的指针用)

对结构体的操作就是对成员的一个个操作。而对结构体的整体操作只有两种情况:

(初始化时,变量直接赋值; 两个同类型的结构体相互赋值)

 

结构体数组的赋值尤其要注意(strcpy(stu1.name, "Li Ming");)

指向结构体变量指针的定义:

 

注意:不能用指向结构体变量的指针指向该结构体变量的某个成员。

 

p是结构体类型,而stu.num属于 int 型(不匹配);

4、访问结构体成员变量的三种方法:

 

说明:

“->”为指向运算符,是优先级最高的运算符

成员运算符“.”的优先级高于指针运算符“*”,因此采用 “(*p).成员名” 形式时,括号不能省略;

注意以下几种运算:

 

5、在定义结构体变量的同时,可以进行初始化

注意:结构体变量的各个初值用花括号{、}括起来,大括号内各个成员变量的值之间用逗号分隔,其值必须与成员变量一一对应,且数据类型应与成员变量一致。

 

 

6、结构体数组的初始化

 

数组中各个元素的初值用大括号{、}括起来,同一数组元素的各个成员变量的初值用逗号分隔。stu[ ]:省略数组大小,必须提供所有的初始值;数组的定义(初始化下标大小;初始值数值;(必须有其中一个))。a[ ][ ],第一个方括号可以为空,第二个不行;a[ ][ ][ ]也是一样。

7、字对齐与半字对齐

字对齐:int型变量占四个字节,其他数据类型都按照四个字节的倍数分配(会产生内存空洞)。同类型的变量放在一起可以减少内存空洞

后一个变量若能在前一个变量分配的空间中存放下,则后一个变量不再重新分配空间。

 

半字对齐: short型变量占2个字节

 

若即存在int 与 short 则 按照 int 的字节(字对齐);若 int 与 short 都不存在则按类型相加。

7、union(共用体)
1、union的含义

union(共用体) 使用方法与struct(结构体) 的使用方法相同

当多个基本数据类型或复合数据结构要占用同一片内存时,我们要使用联合体(共用体);

当多种类型,多个对象,多个事物只取其一时(我们姑且通俗地称其为“n 选1”),我们也可以使用联合体来发挥其长处;

 

 

2、大端字节序(网络字节序)

 

CPU是大端字节序还是小端字节序:通过公用体可以知晓(因为共用体的变量占同一段内存)

 

试用共用体验证大小端字节序:

union node
{
int a;
char b; (int a ; 与 char b ; 占同一段旅内存空间。a 占四个字节;b 占一个字节;)
}; (故通过 b 取出 a 的第一个字节,自然可以知道内存的存储顺序)

int main()
{
union node c;
c.a =1;

if(c.b == 1)
printf("small!\n");
else
printf("big!\n");

return 0;
}

8、enum
枚举类型声明代表常量的符号名称。

enum的默认值

enum kids{nippy, slats, skippy, nina ,liz};

enum kids a; a = nippy;

enum的指定值

enum levels {low=100,medium=500,high=2000};

enum levels a; a = low; (a = 100 (错误))a 不是整形 是枚举类型

若枚举常量没有取值:默认:第一个为 0;后一个枚举常量是前一个值加1;

enum的用法

作为switch的标签

9、typedef
typedef是C语言的关键字,其作用是为一种数据类型定义一个新名字

格式:typedef 数据类型 自定义数据类型

typedef unsigned long uint32;

在嵌入式的开发中,由于涉及到移植问题,typedef的功能就更引人注目了。

如:

typedef struct

{ char a;

short b;

char c;

}node;

nade link;(数据结构类型 定义变量(link))

int * ( * ( * fpl)( int ))[10] (见:教你理解复杂的C-C++声明)

10、宏—#define
1、带参数

定义常量与命令(避免幻数)

#define MAX 100 (MAX:宏名 100:宏体)

#define SIZE 1024

#define LOGIN_SUCCESS 1

#define LOGIN_FAIL 0

注意:在宏定义的命名时,尽量能够清晰的表明其用途;

预处理 == 宏展开 == 宏替换(字符替换;不做语法分析、不做运算)

 

2、定义函数

#define MAX(a, b) ((a)>(b)?(a):(b))

宏函数 宏体

宏体 :所有形参 ,以及宏体都要加括号

普通函数:做运算、做语法分析;

宏函数:字符替换;不做语法分析、不做运算(多用于执行频率高且结构简单)

 

#define语句:

#define __DEBUG_

#ifndef __DEBUG_

#define debug_msg(fmt,args...)

#else #define debug_msg(fmt, args...) printf(fmt,

##args)

#endif

#if 0/1

..........

#endif //用于注释代码是否执行

 

二、表达式及语句
1、选择语句(if)
if 语句是C 语言中最简单、最常用的语句,然而很多程序员用隐含错误的方式写if 语句

本节以“与零值比较”为例,展开讨论

布尔变量与零值比较

整型变量与零值比较

浮点变量与零值比较 (用绝对值 :fads 做差,与1e-6比较)

指针变量与零值比较 (与 null 相比较)

2、循环语句(for while do ...while)
for 语句使用频率最高,while 语句其次,do 语句很少用。

重点论述循环体的效率。提高循环体效率的基本办法是降低循环体的复杂性。

在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数;

a与b交换(三种):

a = a+b; b = a -b; a = a - b;

a = a^b; b = a^b; a = a^b;

t = a ; a = b; b = t;

3、switch分支语句
switch语句可以产生具有多个分支的控制流程。

它的格式是:

switch(控制表达式)

{

case常量表达式:语句列表 ;break

case常量表达式:语句列表 ; break

...

default:语句列表 ; break;

}

每个case 语句的结尾不要忘了加break,否则将导致多个分支重叠(除非有意使多个分支重叠);

不要忘记最后那个default 分支。即使程序真的不需要default 处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了default 处理。

4、goto语句
自从提倡结构化设计以来,goto 就成了有争议的语句。首先,由于goto 语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格。其次,goto 语句经常带来错误或隐患。它可能跳过了某些对象的构造、变量的初始化、重要的计算等语句,例如:

goto state; char s1, s2; // 被goto 跳过

int sum = 0; // 被goto 跳过

state:

如果编译器不能发觉此类错误,每用一次goto 语句 都可能留下隐患。

goto只用于跳出多循环

三、位运算
1、按位与──&

主要用途:清0(写0),保留某些位(写1)

2、按位或──|

主要用途:置1(写1),保留某些位(写0)

3、按位异或──^

主要用途:使1个数的某(些)位翻转(即原来为1的位变为0,为0的变为1),其余各位不变。

4、按位取反──~

主要用途:间接地构造一个数,以增强程序的可移植性。

5、按位左移──<<

6、按位右移──>>

说明:

(1)x、y和“位数”等操作数,都只能是整型或字符型数据。除按位取反为单目运算符外,其余均为双目运算符。

(2)参与运算时,操作数x和y,都必须首先转换成二进制形式,然后再执行相应的按位运算。 例如,5<<2=20:0101 → 10100,20 >> 2=5:10100 → 00101

(3)实现&、|、^运算主要用途的方法

1)构造1个整数:该数在要取(或保留)的位、或要置1的位、或要翻转的位上为1,其余均为0。

2)进行按位与、或按位或、或按位异或操作。

(4)实现按位取反主要用途的方法

1)求~0,间接地构造一个全1的数;

2)按需要进行左移或右移操作,构造出所需要的数。 例如,直接构造一个全1的数,在IBM-PC机中为0xffff(2字节),而在VAX-11/780上,却是0xffffffff(4字节)。如果用~0来构造,系统可以自动适应。

 

应用举例 [案例]
从键盘上输入1个正整数给int变量num,输出由8~11位构成的数(从低位、0号开始编号)。

 

程序说明:~ ( ~0 << 4)

按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1;再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要的。

[案例] 从键盘上输入1个正整数给int变量num,按二进制位输出该数。

1.复合赋值运算符 除按位取反运算外,其余5个位运算符均可与赋值运算符一起,构成复合赋值运算符: &=、|+、^=、<<=、>>=

2.不同长度数据间的位运算──低字节对齐,短数的高字节按最高位补位:

(1)对无符号数和有符号中的正数,补0;

(2)有符号数中的负数,补1。
————————————————
版权声明:本文为CSDN博主「充满热情的常春藤叶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_53812805/article/details/122627893

posted @ 2023-12-06 09:04  苍月代表我  阅读(54)  评论(0)    收藏  举报