关键字、数据类型、自定义数据类型与类型修饰符(C语言)

硬件中最小的单位:高低电平;也就是软件中的位。

一、关键字

关键字:编译器预先定义的具有一定意义的字符串。
它就是字符串,只不过被赋予了特定的意义。

C语言有32个关键字。

如:sizeof是关键字,而不是函数。
我们没有实现sizeof,而是编译器规定好的供我们查看内存空间容量的一个工具。

printf是标准库里面的一个函数,借助于操作系统。如果嵌入式开发中没有OS,直接进行裸板操作,就不能调用该函数。但是仍然可以使用sizeof()查看内存空间容量大小。


二、数据类型

计算机:CPU与很多资源,中间通过数据总线和地址总线相连。

C语言的操作对象/目标:资源/内存(硬件资源(显存)、LCD缓存、LED灯、其他的串口和I2C设备等)。

C语言如何描述这些资源的属性?

通过资源属性的大小——即数据类型关键字:它是限制内存(土地)大小的关键字。
因此,要记住每个数据类型的大小。

涉及到数据类型大小,一般情况下都不是定值,与编译器有关,由编译器决定。

1、char

硬件芯片操作的最小单位。bit:1和0;高低电平;位。
char buf[x];能更好地处理硬件所发送或接收的数据。

如果软件操作的最小单位和硬件一样,那开发量会非常庞大。因此软件采用了集合方式,把一组bit当作软件操作的单位:8bit == 1Byte (1B),字节
ASCII码表:在整个计算机的键盘中,用8bit不同的状态可以描述所有的键值。

2、int

其大小就是编译器最优的处理大小,即系统一个周期所能接收的最大处理单位。

比如:

  • 32位系统,一个周期能处理的数据是32bit。则:32b(4B)就是int的大小,此时编译器最优。
  • 16bit的单片机系统,则int大小就是2B(16bit),此时编译器最优。

如果是数字的处理(循环、计数器等),用int比用char好。

3、short

如果没有特殊要求,用int而不用short;除非对空间有非常强烈的限制,比如在32位电脑中,必须要求空间是16bit处理,则使用short。

4、long、long long

它们是C语言可扩展的类型,要看编译器是否支持。


三、自定义数据类型

C编译器默认定义的内存分配不符合实际资源的形式。

自定义=基本元素的集合

1、struct:元素之间的合集

struct myabc
{
    unsigned int a;
    unsigned int b;
    unsigned int c;
    unsigned int d;
};  
// 这是声明,只是告知编译器,具有内存空间定义的能力,但是还没有进行定义。

struct myabc mybuf;   // 这是定义

注意:结构体中顺序是有要求的。

2、union:共用起始地址的一段内存

在一些技巧型的代码中会用到。

union myabc{
    char a;
    int b;
};    // 声明
union myabc abc;    // 定义

3、enum:枚举(整型常数的集合)

定义常数:

#define MON 0
#define TUE 1
#define WED 2

enum与define是一致的,只不过enum可以更好地描述一个对象集合。

enum 枚举名称{常量列表};

enum abc {MOD, TUE, WED};    //不管定义多少个,一次只取一个,存在32bit的空间中。

用处:比如,一个芯片中有一些数字1、2、3,另一个芯片中也有一些数字1、2、3,但是代表不同的芯片不同的含义,因此两个芯片分别定义一个enum,就可以用一些独有的名字来代表1、2、3,让人一看就明白。

程序员读数字看不懂什么意思,但是通过看名字就能看得懂了

enum就是一个让程序员与程序员交流上更加便利的一种打包的常量集合的概念。

例子:

/*001.c*/
#include <stdio.h>
enum abc {MOD=100, TUE, WED};
int main()
{
    enum abc a1=MOD;
    printf("the a1 is %u:%d\n",sizeof(a1),a1);
    printf("the %d\n",MOD);
    return 0;
}
/*002.c*/
#include <stdio.h>
enum abc {MOD=100, TUE, WED};
int main()
{
    enum abc a1 = 800;
    printf("the a1 is %u:%d\n",sizeof(a1),a1);
    printf("the %d\n",MOD);
    return 0;
}

4、typedef

见:《typedef(C语言)


四、类型修饰符

对内存资源在内存中的存放位置的限定。

对于嵌入式开发工程师而言,内存分配的具体位置实际上与某些代码和流程非常有关系。

在内核和驱动编程中,类型修饰符会被大量地使用。

要对类型修饰符有比较深入的总结才行。

1、auto

是一种默认情况,分配的区域是在可读可写的内存上。

auto int a;
auto long b;

区域如果在{ }中,则是栈空间。

2、register

分配的区域是在寄存器上。
因此,register可以定义一些快速访问的变量。即,如果某个变量访问的频率很高,就使用register修饰,可以尽量放在寄存器中。

寄存器:CPU缓存器
内存:内部存储器

register int a;
// 编译器不是一定会把a放在寄存器中
// 编译器会尽量地安排CPU的寄存器去存放a。但如果寄存器空间不足时,a还是会被存放在存储器中

register只是告诉编译器尽量去安排,但是如果确实寄存器空间不足时,它是没有任何办法的,所以它没办法一定能确定存储的位置,因此,&取地址符号对register不起作用。

中看不中用!

// 003.c
#include <stdio.h>
int main()
{
    register int a;
    a = 0x10;
    printf("a is %d\n", a);
    return 0;
}
// 004.c
#include <stdio.h>
int main()
{
    register int a;
    a = 0x10;
    printf("a is %d\n", &a);
    return 0;
}

register虽然功能不是很强大,它无法确定一定会存储在寄存器上;但是当程序员看到register修饰的变量后,就能够知道一点:该变量的访问一定很频繁!

3、static

在多文件工程编程中,在内核中,会大量地看到static在用。

在嵌入式C中的3种应用场景(修饰3种数据):

(1)修饰函数内部的变量:局部变量

int fun()
{ 
    int a; ===> static int a;
}

(2)修饰函数外部的变量:全局变量

int a;     ===>  static int a;
int fun()
{

}

(3)修饰函数

int fun();  ===> static int fun();

函数也可以理解成是一种变量。

// 005.c
#include <stdio.h>
int main()
{
    printf("main is %d\n", main);
    return 0;
}
函数名也是一个值

4、extern

外部声明。主要在全局变量和函数中使用。

5、const

本意:用于定义常量(经const修饰就不能改变了)
实际:只读的变量(这个变量还是可以通过某些方法来改变的)。

const是C语言的软肋!中看不中用!!

const int a  = 100;

// 编译器不允许进行显式地修改
a = 200;

// 但是还是有办法来对a进行修改的
  • 内存泄漏

    char *p;
    
    // 这2个等价
    const char *p;    // 建议用它     
    char const *p;  
    // 建议p指向的内存空间,内容是只读的。
    // p是1字节1字节(char)去读的。p可以指向任意空间,但是只要指向了,就建议它的内容是只读的。  
    // ——可理解为:字符串。
    
    // 这2个等价
    char * const p;    // 建议用它    
    char *p const; 
    // 建议p永远指向第一次指向的地址。它指向固定地址,但是地址里面的内容是可以变的。
    // 一般这种定义,都是硬件资源的定义。比如,缓存地址是焊好的,或者芯片做的时候就做死了,但是里面的内容是可以变的。
    
    const char * const p;     // 限制更加严格。它指向的地址不能变,里面的内容也不能变。
    // 工程中使用得不多,硬件中描述比较多。比如,描述ROM设备
    

例1:

// 001.c
#include <stdio.h>
int main()
{
    char *p = "hello world\n";    // 双引号表示整型常量,里面的内容是不可变的
    printf(" the first world is %x\n", *p);
    *p = 'a';
    printf("p is %s\n", p);
}
段错误:指针指向的内容被非法访问/修改了

例2:

// 002.c
#include <stdio.h>
int main()
{
    char buf[] = {"hello world\n"};
    char *p = buf;
    printf("the first world is %x\n", *p);
    *p = 'a';
    printf("p is %s\n", p);
}
数组内容是可以改变的

例3:

// 003.c
#include <stdio.h>
int main()
{
    const char *p = "hello world\n";    // 直接用const修饰只读内容
    printf(" the first world is %x\n", *p);
    *p = 'a';
    printf("p is %s\n", p);
}
使用const后,非法访问/修改指针指向内容时,会直接报错

例4:

// 004.c
#include <stdio.h>
int main()
{
    const int a = 0x12345678;
    int b = 0x11223344;
    int *p = &b;
    *(p+1) = 0x100;    // p+1:a的地址
    printf("a is %x\n", a);
}
虽然a用const修饰,无法直接修改值;但通过越界,将a的值修改了

const只是建议,不是强制。只是编译时不会变,运行时如果通过越界访问,也可以改变。

6、volatile

它不是限定内存存放位置的修饰符,而是告知编译器编译方法的修饰符。

告知编译器:不优化编译。

volatile的使用与地址关系比较大;在嵌入式和驱动开发中,与硬件打交道比较多。在上层开发中,几乎看不到这个关键字。

volatile修饰变量的值的修改,不仅仅可以通过软件,也可以通过其他方式(硬件外部的用户)。

例子:键盘按下,值改变,LCD亮。

volatile char *p;
*p == 0x10;    // 会一直从里面读,而不会优化掉。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容