int b = a << 2; /* b = 0111 1000 =240 */ /* ... 利用PI... */ #undef PI/* 之后PI不再是一个宏 */
复制代码
宏定义的注意事项
l 宏定义只是简单的文本替换,没有类型检查或作用域限制。
l 宏大概会因为参数的运算符优先级导致预期之外的举动,所以利用时要特别警惕。
l 宏定义大概会导致代码膨胀,因为每个宏的利用都会导致相同代码的重复插入。
l 避免在宏中利用复杂的表达式或逻辑,因为这会增加代码阅读和维护的难度。
l 利用宏时要谨慎,以避免出现不测的副作用或难以调试的错误。
在这个例子中,FEATURE_A被定义了,所以#ifdef FEATURE_A和#endif之间的代码会被编译。而FEATURE_B没有被定义,所以#ifndef FEATURE_B和#endif之间的代码会被编译。
除了#ifdef,另有其他的条件编译指令:
l #ifndef:假如宏没有定义,则包含代码。
l #if:用于检查宏是否定义以及它的值是否为真(非零)。
l #elif:与#if和#else团结利用,用于检查多个条件。
l #else:假如前面的#if或#ifdef条件不满足,则包含代码。
l #endif:标志条件编译块的结束。
这些指令通常在源代码的顶部利用,以根据特定的设置或平台条件包含或清除代码段。例如,你大概想要在不同的操作系统上利用不同的系统调用,大概在调试和发布版本中包含或清除调试代码。 5.4 extern外部申明
在C语言中,extern关键字用于声明一个变量或函数,而不是定义它。extern告诉编译器,变量的定义或函数的实现在其他地方,大概是在另一个源文件中。这允许程序的不同部分共享同一个变量或函数,而无需在每个文件中都重复定义它。
1,变量外部声明
当你想在一个源文件中利用另一个源文件中定义的变量时,你必要利用extern来声明这个变量。例如,假设你有一个名为variables.c的文件,它定义了一个名为globalVar的全局变量:
printf("Thevalue of globalVar is: %d\n", globalVar);
return 0;
}
复制代码
在这个例子中,main.c中并没有定义myFunction,而是通过extern关键字举行了声明。在编译和链接阶段,链接器会找到myFunction的定义,并将其与main.c中的调用关联起来。
3,注意事项
l extern只能用于声明变量或函数,不能用于定义。定义会分配内存空间,而声明不会。
l 当你在一个源文件中定义了一个变量或函数,并想在另一个源文件中利用它时,你必要在第二个源文件中利用extern举行声明。
l 外部声明必须在利用变量或函数之前举行。
l 在链接阶段,链接器会查找所有extern声明的定义,假如找不到,就会出现链接错误。
l 假如多个源文件定义了同一个extern变量,那么链接器会将其视为错误,因为同一个变量只能有一个定义。但是,多个源文件可以包含同一个extern函数的声明,因为这个函数大概在不同的地方有不同的实现。 5.5 typedef类型别名
typedef用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。例如在编写程序时经常利用到的uint8_t、uint16_t和uint32_t等都是由typedef定义的类型别名,其定义如下:
如上,就定义一个名为p_str的指针变量,并将p_str指针指向了字符串“This is a string!”保存在内存中首地点,对于ESP32来说,此时p_str的值就是一个32位的数,这个数就是一个内存地点,这个内存地点就是上述字符串保存在内存中的首地点。
通过p_str指针就可以访问到字符串“This is a string!”,那具体是怎样访问的呢?前面说p_str保存的是一个内存地点,那么就可以通过这个内存地点去内存中读取数据,通过p_str就可以访问地点为p_str的内存数据,(p_str + 1)可以访问下一个内存地点中的数据。
知道了怎样访问内存中的数据,但是读取到的数据要怎样解析呢?这就有p_str指针的类型决定了。在这个例子中p_str是一个char类型的指针,那么访问p_str就是访问地点为p_str,巨细为sizeof(char)(一般为一个字节)的一段内存数据,在这个例子中就可以读取到字符“T”, 读取(p_str+ 1)就是“h”,以此类推。
为了更加直观的演示,我们试着编写如下代码并观察输出结果的变革: