目录
1,类型:char、short、int、long、float、double、_Bool、auto、struct、enum、union
2,循环和分支:do、while、for、switch、case、default、break、continue、if、else、goto
3,其他:return、void、static、inline、extern
本文列举的是C11所有关键字。
一,类型相关关键字
1,类型:char、short、int、long、float、double、_Bool、auto、struct、enum、union
2,类型修饰:signed、unsigned
signed和unsigned相对,signed表明是有符号整数。
一般的整数类型,不加unsigned修饰的,默认都是signed
唯独char这个整数类型,默认的是unsigned还是signed是不确定的,这时可以用signed来修饰。
说来说去还是感觉鸡肋啊。
3,typedef
(1)typedef——起别名
typedef int INTEGER
INTEGER a,b;
它等效于:
int a,b;
(2)typedef 数组
typedef char NAME[20];
NAME a1,a2,s1,s2;
完全等效于:
char a1[20],a2[20],s1[20],s2[20]
(3)typedef 和 结构体(数组)
示例:
typedef struct struc
{
int a;
int b;
}stru,stru2[3];
int main()
{
stru s1;
stru2 s2;
s1.a=1,s2[0].b=2;
cout<<s1.a+s2[0].b;
return 0;
}
注意区分不用typedef的普通写法:
struct struc
{
int a;
int b;
}stru,stru2[3];
int main()
{
stru.a=1,stru2[0].b=2;
cout<<stru.a+stru2[0].b;
return 0;
}
两个程序的逻辑一样,输出结果都是3
(4)typedef 和 宏
有时也可用宏定义来代替 typedef 的功能:
typedef 原类型名 新类型名
#define 新类型名 原类型名
但是宏定义是由预处理完成的,而 typedef则是在编译时完成的,而且typedef的带数组的用法是不能用宏替代的。
(5)typedef 函数指针
示例:
typedef char (*func)(int);
char GetChar(int a)
{
return '0' + a%10;
}
int main()
{
func f=GetChar;
cout<<f(5);
return 0;
}
输出:
5
4,sizeof
sizeof用来求出所占的字节数
sizeof是个关键字,不是函数,sizeof是在编译期间求值。
(1)基本类型和类的大小
cout<<sizeof(char)<<" "<<sizeof(int)<<" "<<sizeof(string)<<" "<<sizeof(vector<int>);
1 4 32 20
类的大小都是固定的,和对象无关,具体怎么算没仔细研究,好像是只和成员变量和虚函数表有关。
(2)数组的大小是数组所占内存的总大小,指针的大小是系统的大小
代码:
int a[]={0,1,2,3,4,5};
int *p=a;
cout<<sizeof(a)<<" "<<sizeof(p);
输出:
24 4
PS:
我们用64的win10操作系统的时候,指针应该是8个字节,但是编译器往往选择编译成32位的程序,所以这指针还是4个字节。
(3)数组和指针作为参数传递时,都是传递指针
代码:
int getSize(int x[])
{
return sizeof(x);
}
int getSize2(int* p)
{
return sizeof(p);
}
int main()
{
int a[]={0,1,2,3,4,5};
int *p=a;
cout<<getSize(a)<<" "<<getSize(p)<<" "<<getSize2(a)<<" "<<getSize2(p);
return 0;
}
输出:
4 4 4 4
(4)char数组表示的字符串
代码:
char s1[]="abcdef";
char s2[]="";
cout<<sizeof(s1)<<" "<<sizeof(s2);
输出:
7 1
二,其他常用关键字
1,const
const可以修饰普通变量,表示不可更改值。
const还可以修饰指针,有2种修饰,一个是指针本身的值不可更改,一个是指针指向的地址的值不可更改,所以会有4种写法。
对于非const变量,这4种写法都是可以的:
int main()
{
int x = 10;
// int* p = &x;
// const int* p = &x;
// int* const p = &x;
const int* const p = &x;
cout << *p;
return 0;
}
对于非const变量,只有2种写法:
int main()
{
const int x = 10;
// int* p = &x; //not ok
// const int* p = &x; //ok
// int* const p = &x; //not ok
const int* const p = &x; //ok
cout << *p;
return 0;
}
2,循环和分支:do、while、for、switch、case、default、break、continue、if、else、goto
goto示例:
int x=0;
while(true)
{
lb:
cout<<x++;
goto la;
}
while(true)
{
la:
if(x>100)break;
goto lb;
}
自定义标签,goto任意跳转,因为比指针还野,所以基本是被封杀的。
3,其他:return、void、static、inline、extern
三,非常用关键字
1,register
把变量放在寄存器中而不是内存中,加快运算速度。
在C++11中,这个关键字失去了作用,是否放寄存器完全由编译器优化来决定。
2,restrict
用来修饰指针,表明该指针所指向的位置的值只能通过该指针修改
3,_Complex
表示复数
4,_Imaginary
表示虚数
5,_Noreturn
修饰函数,指定函数不会由于执行到 return 语句或抵达函数体结尾而返回。
6,_Static_assert
用于编译时断言,类似条件编译。
7,_Generic
_Generic可以获取变量的类型,用于泛型选择表达式,实现轻量级的泛型程序设计。
#define MYTYPE(x) _Generic(x, int:"int32", double: "double64")
printf("%s ", MYTYPE(0));
printf("%s ", MYTYPE(0.0));
输出:
int32 double64
8,volatile
volatile表示,代理(而非程序本身)可以改变变量的值。
如果没有volatile关键字,编译器就默认只有程序内部才能改变变量的值,这样就可以进行一些编译优化。
const 和 volatile可以同时修饰一个变量,表示程序内部不能更改值,但是代理可以更改值。
9,_Atomic
表示原子操作
10,_Thred_local
_Thred_local表示线程变量
C语言存储类别、存储区_nameofcsdn的博客-CSDN博客
11,_Alignas、_Alignof
这2个关键字都是内存对齐相关的,_Alignof用于获取对齐值,_Alignas用于设置对齐值。
int len = 10;
printf("%d",_Alignof(len));
输出:4
struct S{
_Alignas(16) int x;
};
printf("%d",sizeof(struct S));
输出:16