【C语言 | 关键字】C语言32个关键字详解(1)—— 数据类型部分(char、short、int、long、float、double、struct、union、enum、void)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍标准C语言的32个关键字🍭
😎金句分享😎:🍭有机会一定要试试,其实试错的成本并不高,而错过的成本很高🍭

C语言32个关键字详解(1):数据类型部分(char、short、int、long、float、double、struct、union、enum、void)
C语言32个关键字详解(2):修饰类型部分(auto、signed、unsigned、static、extern、const、register、volatile)
C语言32个关键字详解(3):结构语句部分(if、else、switch、case、default、do、while、for、break、continue、return、goto)
C语言32个关键字详解(4):其他(typedef、sizeof)


在这里插入图片描述

一、概述

C语言有多少个关键字?各个关键字有什么作用?本文将详细介绍C语言的关键字,可能一篇文章写不完 ,将在后面文章继续完善。C语言的关键字有32个,我将它主要分成下面四个方面来介绍。

功能关键字
类型(10个)char、short、int、long、float、double、struct、union、enum、void
修饰类型(8个)auto、static、extern、register、volatile、const、signed、unsigned
结构语句(12个)do、for、while、break、continue、goto、if、else、switch、case、default、return
其他(2个)typedef、sizeof

在这里插入图片描述

二、什么是定义?什么是声明?

在学习下面的基本数据类型前,先弄清楚定义和声明有什么区别?怎么区分呢?
下面这两句代码,哪个是声明,哪个是定义?

char c;
extern int i;
  • 定义:是分配一块内存,并给这块内存取一个名字,这个名字就是变量名;
    在该变量的所在区域内,该变量只能被定义一次;
    定义的同时可以初始化。
  • 声明:告诉编译器,这个名字已经在使用了,下面代码用到该名字是在其他地方定义的;
    声明可以出现多次;
    声明不能初始化;
    如果变量或函数在其他文件定义的,声明时必须加extern修饰,如果定义在本文件,则加不加extern都可以。

可以参考下面代码加深理解:

//extern.c
int extern_val;
int get_extern_val()
{
	return extern_val;
}

复制上面代码保存为extern.c;

// main.c
#include <stdio.h>

extern int extern_val; 		// 声明,变量定义在其他文件(extern.c)
extern int get_extern_val();// 声明,函数定义在其他文件(extern.c)

extern int val;				// 声明,变量定义在本文件
extern int get_val();		// 声明,函数定义在本文件

// 下面是不加extern的声明,声明可以多次 2023-09-30 16:39:16
int val;		// 不加extern的声明,变量定义在本文件
int get_val();	// 不加extern的声明,变量定义在本文件

int main()
{
	extern_val = 0;
	get_extern_val();
	val = 1;
	get_val();
	return 0;
}

int val=1;
int get_val()
{
	return val;
}

复制上面代码保存为main.c;
在Ubuntu 18.04系统使用版本为7.5的gcc编译器,通过命令gcc main.c extern.c可以正常编译上面代码。
在这里插入图片描述

在这里插入图片描述

三、基本数据类型 : char、short、int、long、float、double

在32个关键字中,C语言的基本数据类型就占用了6个了,这些基本数据类型主要用来定义变量或者作为函数的参数或返回值类型。

类型大小(32位系统)大小(64位系统)
char1个字节1个字节
short2个字节2个字节
int4个字节4个字节
long4个字节8个字节
float4个字节4个字节
double8个字节8个字节

在这里插入图片描述

3.1 类型转换

C语言中,整型、单精度型、双精度型和字符型数据可以进行混合运算,但不同类型运算时会发生隐式类型转换:

  • 整型提升规则:char、short、int、long四个类型混合运算时,较小的(占用字节数小)整数类型会被自动提升为较大的(占用字节数大)整数类型,以确保不会丢失精度。字节数小于int型的会直接提升为int类型。
    char类型short类型混合运算的结果是int类型
    long类型long long 类型混合运算的结果是 long long类型
    signed类型unsigned类型混合运算的结果是 unsigned类型
  • 浮点数提升规则:整型(char、short、int、long)和浮点类型(float、double)混合运算时,会自动提升为浮点类型;而且,较短的浮点数类型(如float)会被自动提升为更长的浮点数类型(如double)以进行混合运算,以确保不会丢失精度。

赋值时类型转换:赋值时会隐式转换为=左边的类型;

强制类型转换:在数字或变量前加(类型),进行强制转换;
如:char ch = (char)35;

3.2 数据类型 与 模子

数据类型就像模子一样,以内存为材料,打造出具有不同字节的变量。
当你定义一个char型变量时,就像用拥有一个字节的“模子”从内存咔出来一个字节大小的“饼”;
当你定义一个int型变量时,就像用拥有四个字节的“模子”从内存咔出来四个字节大小的“饼”;

总之,当使用数据类型定义变量,本质上就是从内存中取出一块该类型大小的内存,并给这个内存定义一个唯一的名字。
在这里插入图片描述

3.3 变量命名规则

  • 命名最好采用英文单词或其组合,别使用拼音,可望文知意,便于记忆和阅读;

  • 尽量避免名字中出现数字编号,如 Value1,Value2 等

  • 对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名(缩写)作为范围限定符)。 (GUI_ , etc)

  • 由多个词组成时,每个词的第一个字母大写,其余全部小写,比如:int CurrentVal;,或用下划线隔开,如:int current_val;

  • 程序中不得出现仅靠大小写区分的相似的标识符,如:int x, X;

  • 所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词:
    const int MAX_LENGTH = 100;#define FILE_PATH “/usr/tmp”

  • 定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据。

  • 不同类型数据之间的运算要注意精度扩展问题,一般低精度数据将向高精度数据扩展

  • 命名可以参考下图规范,按照标识符前缀(后缀) + 含义标识 。非全局变量可以不用使用范围限定符前缀。
    在这里插入图片描述

  • 作用域前缀命名规则:
    全局变量、函数(global):g
    静态变量、函数(native):n

  • 数据类型前缀命名规则:

数据类型前缀命令例子
boolean类型bboolean bVariable;
char类型cchar cVariable;
int类型iint iVariable;
short类型sshort sVariable;
long类型llong lVariable;
unsigned类型uunsigned int uiVariable;
double 类型ddouble dVariable;
float 类型ffloat fVariable;
  • 含义标识命名规则,变量命名使用名词性词组,函数命名使用动词性词组。

在这里插入图片描述

四、构造类型:struct、union、enum

4.1 struct 关键字

struct 关键字,会将一些相关联的数据打包成一个整体,方便使用。

程序开发过程中经常要传送的不是简单的字节流(char 型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体,如果将这样的数据放在char型数组中,再使用指针偏移去获取数据,会使编程变得很复杂,而使用struct关键字定义的结构体可以轻松解决这种问题。

另外,当函数参数超过4个时,使用起来容易出错,降低效率,可以使用结构体压缩形参。

4.1.1 结构体大小

结构体所占的内存大小是其成员所占内存之和。如果结构体里没有成员,它的大小会跟编译器有关,下面代码,在Ubuntu18.04 使用gcc编译器编译后,没有成员的结构体大小是0,使用g++编译器编译后,没有成员的结构体大小是1.

// main.c
#include <stdio.h>
typedef struct stStudent
{

}stStu;
int main()
{
    printf("%ld\n",sizeof(stStu));
    return 0;
}

在这里插入图片描述

4.1.2 柔性数组(可变长数组)

C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。 sizeof 返回的这种结构大小不包括柔性数组的内存。柔性数组的定义可以参考下面代码,虽然定义了arr数组,但它并没有使结构体占用的内存增加,整个stStu的大小还是4个字节:

typedef struct stStudent
{
    int i;
    int arr[];	// 没指定数组大小
}stStu;typedef struct stStudent
{
    int i;
    int arr[0];// 指定数组大小为0
}stStu;

柔性数组的使用可以参考下面代码,定义结构体指针pStu指向malloc分配的一块内存,然后就可以通过pStu->arr[n]去访问数组元素,因为这块内存是malloc分配的,如果arr后面的空间不够的话,就可以动态去调整,这就是被成为柔性数组或可变长数组的原因:

stStu *pStu = (stStu*)malloc(sizeof(stStu)+100*sizeof(int));

完整使用例子如下:

// flexible_arr.c 2023-10-06 21:06:04
#include <stdio.h>
#include <stdlib.h>

typedef struct stStudent
{
        int i;
        int arr[];
}stStu;
int main()
{
        stStu *pStu = (stStu*)malloc(sizeof(stStu)+100*sizeof(int));
        printf("stStu=%ld pStu=%ld\n",sizeof(stStu),sizeof(*pStu));

        int i=0;
        for(i=0; i<10; i++)
        {
                pStu->arr[i] = i;
        }
        printf("arr:");
        for(i=0; i<10; i++)
        {
                printf("%d,",pStu->arr[i]);
        }
        printf("\n");
        return 0;
}

4.2 union 关键字

union关键字的用法和struct关键字非常相似,不过union只会分配一个空间来给所有成员共同使用,这个空间大小是所有成员中占用字节数最大成员决定的,所以所有成员具有相同的起始地址,同一时间只能存储一个成员的数据。

union主要用来压缩空间,如果某些数据在同一时间不会一起使用,可以使用union;

4.2.1 union类型的定义

一般定义方式:union 类型名{ 成员列表};

union check
{
    int i;
    char ch;
} c;

4.2.2 union关键字与系统大小端

系统的存储模式分为小端模式和大端模式:

  • 小端模式:数据的低字节存储在低地址;高字节存储在高地址;
  • 大端模式:数据的高字节存储在低地址;低字节存储在高地址;
    在这里插入图片描述

可以使用下面代码测试系统大小端模式:

// union
#include <stdio.h>
int checkSystem( )
{
    union check
    {
        int i;
        char ch;
    } c;
    c.i = 1;
    return (c.ch ==1);
}
int main()
{
    printf("system is %s\n",checkSystem()?"Little endian":"Big endian");
    return 0;
}

4.3 enum 关键字

enum在实际开发中很常用,也用得很简单。主要就是用enum来定义一定范围内的常量。

4.3.1 enum(枚举)类型的定义

一般定义方式:enum 枚举名{ 枚举值表 };

enum PictureFormat
{
	JPEG,
	BMP,
	PNG,
};

上面代码定义之后,JPEGBMPPNG就可以被当作常量在代码中使用了,所以同一区域内不能再定义其他枚举类型含有JPEGBMPPNG枚举值,否则会报错:

注意:

  • 定义时,枚举值(枚举常量)一般使用大写字母;
  • 每个枚举值后都使用 , 隔开,而不是 ;
  • 定义时,枚举值可以指定,指定后从那个常量开始依次加1:enum{PIC_ONE=1, PIC_TWO,};
    也可以不指定,枚举值从0开始依次加1:enum{PIC_ZERO, PIC_ONE, PIC_TWO,};
  • 枚举类型定义后,枚举值可以在代码中直接使用,且同一区域内,已经定义过的枚举值不可再被其他枚举类型包含;

4.3.2 enum(枚举)变量

枚举变量可以和枚举类型一起定义:

enum PictureFormat
{
	JPEG,
	BMP,
	PNG,
}top_pic, bottom_pic;

也可以先定义枚举类型,再定义枚举变量

enum PictureFormat
{
	JPEG,
	BMP,
	PNG,
};
enum PictureFormat top_pic, bottom_pic;

注意:

  • 不能直接将数字赋值给枚举变量,确实需要赋值,可以使用强制类型转换:
    enum PictureFormat pic=3; //错误
    enum PictureFormat pic=(enum PictureFormat)3; //正确
  • 枚举变量在一般情况下,只允许被该类型的枚举值赋值;
  • sizeof查看枚举类型、枚举变量占用的空间是4个字节。

在这里插入图片描述

五、void 类型

void类型不能定义变量;
void*指针可以接收任意类型指针的赋值;

void 真正发挥的作用在于:
(1) 对函数返回的限定;
(2) 对函数参数的限定。

限定返回值:
在 C 语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。
因此,为了避免混乱,我们在编写 C 程序时,对于任何函数都必须一个不漏地指定其类型。如果函数没有返回值,一定要声明为 void 类型。

限定参数:

#include <stdio.h>
fun()
{
	return 1;
}
int main()
{
	printf("%d",fun(2));
	getchar();
}

上面代码使用gcc编译器可以编译通过,fun函数没注明返回值和参数,调用时却可以使用参数,虽然gcc编译器可以编译通过,却不建议这样使用,会加大阅读代码的难度。如果函数定义时确定了不需要使用参数,应该使用void限定参数列表,避免歧义。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wkd_007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值