8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
文章目录
编译器指令,或者叫做预处理指令(Preprocessor),指的是在程序用编译器翻译为机器可以识别和执行的指令前,所做的指令操作。它可以控制程序在不同执行状态下执行不同的结果。为区分其他编程语句,我们使用井号 #进行开头。
#include 指令
这个指令用于导入头文件。什么是头文件呢?在使用特定的编程函数,诸如 printf、scanf 等时,由于每一个编程函数都有不同的功能,所以为了方便管理,它们各自被放在不同的头文件下,在使用时,需要根据它本身属于哪个头文件,先要导入,才能使用。否则编译器找不到这个函数。
它有两种导入方式:引号导入和尖括号导入。如果写成这样:1
则表示它是一个系统自带的编程函数。它会先找系统自带的函数库,发现文件存在就可以打开。如果不存在,再找到你建立这个C语言程序代码下,文件夹下是否有这个头文件。
反之,如果要先找当前文件夹下的头文件的话,我们使用引号导入。1#include "test.h"
注意,编译器指令都是不用分号结尾的。
#define 指令
真·常量定义
它又被称为宏定义(Macro Defining),是将代码里所有代码的写法替换成宏定义过的写法。比如,在代码里写很多计算圆的公式,它会大量使用到圆周率的值(约 3.14159),可如果代码内直接写值的话,如果需要对代码作改动,就需要挨个改掉它们,就相对麻烦,这个时候我们可以使用 #define 指令替换它们,然后改值时,只需要改 #define 一处的值即可。1
2
3
4
5
6
7
8
9
10
11
12#define pi 3.14159
int (void)
{
int i;
scanf("%d", &i);
float area = pi * i * i;
printf("%.2f", area);
return 0;
}
另外,一般而言,像是这样的指令写的东西(3.14159)是一个常数,所以我们一般将常数全部大写变量名,即 PI 的形式,不过这只是一般而言,也可以不大写。
骚操作
不过,宏定义下的写法是直接替换的,也就是说,你这么写完全可以:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#define 定义一个整型变量 int
#define 主函数 main
#define 无参数 void
#define 输入 scanf
#define 定义一个单精度小数型变量 float
#define 圆周率 3.14159
#define 输出 printf
#define 返回 return
#define 。 ;
#define 值为 =
#define 开始 {
#define 结束 }
#define 取变量地址(a) &a
整型 主函数 (无参数)
开始
定义一个整型变量 整型变量。
输入("%d", 取变量地址(整型变量))。
定义一个单精度小数型变量 面积 值为 圆周率 * 整型变量 * 整型变量。
输出("%.2f", 面积)。
返回 0。
结束
// 程序结束
只是,一部分 IDE,例如 DevCpp 的编译器不能执行中文字符的宏定义替换罢了。不过,#define 定义语句中间的空格是严格规定的,只能在 #define 后和定义名称后有空格,这样来控制替换,否则系统会无法判别。
宏定义有时候也会背锅
另外,#define 有一处需要注意的替换。它甚至可以替换函数,但函数的替换方式可能有一些恶心:1
2#define f(a,b) (a)*(b)
#define g(a,b) a*b
它们是不同的。1
2
3
4int a = 2, b = 3;
int c, d;
c = f(a + a, b + b); // (2 + 2) * (3 + 3)
d = g(a + a, b + b); // 2 + 2 * 3 + 3
看懂了吗?上面的 a 和 b 都有括号,所以下面替换后,也带括号;上面没有括号,下面也没有括号。于是根据优先级的不同,计算结果分别是 4 * 6 = 24 和 2 + 6 + 3 = 11。
#undef 指令
甚至还可以使用 #undef 定义名 的方式来撤销结束定义。比如1
2
3
4
5
6
7
8
9
10
11
12#define pi 3.14159
int ()
{
int r = 6;
int area = pi * r * r;
#undef pi
int c = 2 * pi * r; // Wrong.
return 0;
}
#define 符号指令
我们也可以在定义符号的时候不为其赋值:1#define clang
这样定义的符号在本文件里的任意位置都可以用,或你把它写进头文件里,然后对其使用了 #include 引入了这个头文件时可用。
这种用法需要配合下面要说到的 #if 指令才能发挥作用。
#if、#else、#elif 和 #endif 指令
这四个指令单纯就是为了和 C++ 语言配合使用得比较多。在 C++ 里,有些常量的定义数值是和 C 不一致的,好在它提供了 #define 的宏指令指定了语言类别。
在 C++ 里,系统定义了 __cplusplus 符号。如果我们查看 __cplusplus 符号是否存在,就可以判断当前使用的文件和语言是 C 语言还是 C++,进而去区分程序的执行代码。1
2
3
4
5#if defined __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
例如上面的 5 行指令,先查询当前代码环境是否是 C++。如果是 C++,则会执行第 2 行的 #define 定义语句,让 NULL 常量定义为 0(这是 C++ 里的定义方式。C++ 的空是用 0 表示而不是 (void *)0 表示的;否则,没有查到 __cplusplus,说明是 C 语言环境,那么 NULL 的定义方式就是(void *)0 了。
另外,#if defined 可以简写为 #ifdef 指令:1
2
3
4
5#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
另外,你对条件取反,也是被允许的:1
2
3
4
5#ifdef !__cplusplus
#define NULL ((void *)0)
#else
#define NULL 0
#endif
你也可以使用 #ifndef 指令来表达:1
2
3
4
5#ifndef __cplusplus
#define NULL ((void *)0)
#else
#define NULL 0
#endif
最后,你还可以使用嵌套的方式为其定义。实际上,NULL 常量在头文件里是这么定义的。1
2
3
4
5
6
7
8
9#ifdef __cplusplus
#ifndef NULL
#define NULL 0
#endif
#else
#ifndef NULL
#define NULL ((void *)0)
#endif
#endif
由于头文件 *.h 是不区分 C 还是 C++ 语言的,所以保证程序允许正常,这些指令和赋值都是不可少的。#elif 指令类似于 else if 条件判断,这里就不讲了,因为用的机会很少。
#pragma 杂注指令
最后来说一下杂注(Pragma)。杂注是预处理指令里最复杂的一种,这是因为它的名字“杂注”就表示了所有乱七八糟的指令,不好取名或用得比较少的时候,就直接用 #pragma 指令来搞了,所以它的分支也非常多。我们这里来看一些常用的。至于不常用的,如果你碰到了,直接查询网上给出的文档即可。
#pragma warning 指令
#pragma warning 指令用于忽略、恢复和只提示一次警告信息。假如你的代码里出现了警告错误,例如下面代码1
2int a;
scanf("%d", &a);
这是最基础的使用 scanf 函数的方法了。不过编译器会提出警告 C6031,提示你忽略了 scanf 的返回值。scanf 的返回值表示正确输入到变量里的变量总个数。如果你输入了一个合适的数字,a 正常赋值,那么这个返回值就是 1。
它提示这个信息,提示你最好不要忽略返回值的使用,而是这样用:1
2
3
4
5
6
7
8
9int a;
if (scanf("%d", &a) != 1)
{
// May have bugs...
}
else
{
// Successful.
}
但是,显然我们没有必要这么去处理,因为我们输入一个整数数值是预期的,所以我们可以忽略烦人的警告信息,用法是这样的:1#pragma warning (disable : 6031)
这样的话,你就看不到后续使用的所有有关 scanf 上输入信息的返回值未使用的报错了。
如果你把代码改为1#pragma warning (restore: 6031)
表示从此处开始往下的代码,重新又开始对 C6031 忽略返回值的警告报错。1#pragma warning (once: 6031)
这样则是仅报告一次这样的警告信息,其它的都忽略。
#pragma region 和 #pragma endregion 指令
忘了这个了吗?这个就是最开始介绍的,用于分割语义的指令。这两个指令是配合使用的,用于分割代码段,这一段代码里的所有执行内容表示某个含义。另外,写了这样的指令后,IDE 就可以识别这一块代码是我们指定好的代码块,甚至可以允许我们手动折叠和展开它们。
#pragma once 指令
最后一个指令仅用于头文件里,表示这个头文件只会被编译一次。这是因为,很多时候,相同的指令会被分散放到不同的头文件里;而反之也可能存在多个相同名称的头文件。这样的话,如果我们使用 #pragma once 指令可以保证这个文件整体只会被编译一次,防止多次反复编译出现隐藏的 bug 和错误。
当然,如果执行逻辑都不同的同名头文件最好还是不要用一样的头文件名,防止这些错误的出现。