c primer plus 专题16:C预处理器

1 翻译程序的第一步

c primer plus 专题16:C预处理器_第1张图片

c primer plus 专题16:C预处理器_第2张图片

2 重新定义宏

c primer plus 专题16:C预处理器_第3张图片

3 带参数宏

注意:带参数宏定义中要使用 ( ) 括号将每个参数都包围起来,以免出错。

c primer plus 专题16:C预处理器_第4张图片

4 宏定义创建字符串:#运算符

c primer plus 专题16:C预处理器_第5张图片

执行流程:

c primer plus 专题16:C预处理器_第6张图片

5 预处理器粘合剂:##运算符

c primer plus 专题16:C预处理器_第7张图片

c primer plus 专题16:C预处理器_第8张图片

6 变参宏(... 和 __VA_ARGS__)

c primer plus 专题16:C预处理器_第9张图片

#include 

/* 按照 printf 格式输入时,fmt 为字符串,和前后的黏合起来 */
#define debug(fmt, ...)		printf("<- This is debug mode ->\n" fmt "\n", __VA_ARGS__)
	
int main(void)
{
	debug("debug message print\n");
	debug("%.2f + %.3f = %.5f", 2.1, 3.4, 2.1 + 3.4);

	return 0;
}

7 文件包含 #include 

8 其他指令

1 #undef 指令  取消宏定义

c primer plus 专题16:C预处理器_第10张图片

2 条件编译

2.1 #ifdef    #else    #endif

c primer plus 专题16:C预处理器_第11张图片

2.2 #ifndef    #else    #endif  (常用来防止头文件被重复包含)

c primer plus 专题16:C预处理器_第12张图片

3 #if    #else    #endif

c primer plus 专题16:C预处理器_第13张图片

defined 预处理运算符

c primer plus 专题16:C预处理器_第14张图片

4 预定义宏 (在代码调试中非常有用)

c primer plus 专题16:C预处理器_第15张图片

#include 

int main(void)
{
	printf("This file is %s.\n", __FILE__);
	printf("This function is %s.\n", __func__);
	printf("This date is %s.\n", __DATE__);
	printf("This line is %d.\n", __LINE__);

	return 0;
}

5 #error

c primer plus 专题16:C预处理器_第16张图片

9 断言 assert

C语言提供了断言标准库,#include

c primer plus 专题16:C预处理器_第17张图片

下面是标准库 的说明:

#ifdef NDEBUG

    #define assert(expression) ((void)0)

#else

    _ACRTIMP void __cdecl _wassert(
        _In_z_ wchar_t const* _Message,
        _In_z_ wchar_t const* _File,
        _In_   unsigned       _Line
        );

    #define assert(expression) (void)(                                                       \
            (!!(expression)) ||                                                              \
            (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
        )

#endif

这里有一个疑问,((void)0)是什么意思?

实际上,((void)0)表示一个什么都不做的空语句

参考链接:https://stackoverflow.com/questions/2198950/why-is-void-0-a-no-operation-in-c-and-c

c primer plus 专题16:C预处理器_第18张图片

stm32官方提供的断言机制(也是使用(void(0)) 或者打印文件名和行号)

// 用于断言中检查输入参数
#define IS_GPIO_ALL_INSTANCE(INSTANCE) (((INSTANCE) == GPIOA) || \
                                        ((INSTANCE) == GPIOB) || \
                                        ((INSTANCE) == GPIOC) || \
                                        ((INSTANCE) == GPIOD) || \
                                        ((INSTANCE) == GPIOE) || \
                                        ((INSTANCE) == GPIOF) || \
                                        ((INSTANCE) == GPIOG))

// 使用断言检查参数
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));

// 关于断言的宏定义(默认关闭断言),位于 stm32f1xx_hal_conf.h 文件中
#ifdef  USE_FULL_ASSERT
/**
  * @brief  The assert_param macro is used for function's parameters check.
  * @param  expr If expr is false, it calls assert_failed function
  *         which reports the name of the source file and the source
  *         line number of the call that failed.
  *         If expr is true, it returns no value.
  * @retval None
  */
// 这里使用 (void(0)) 来作为空语句填充
// 如果断言为1,则为空语句;如果断言为0,则调用 assert_failed 函数,这个函数需要我们自己实现
// assert_failed 函数传入了文件和行号等作为形参,我们可以打印来定位错误位置
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */

// 断言函数实现,位于 main.c 中
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
  // 默认为空,这里还给出了推荐用法
	printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}
#endif /* USE_FULL_ASSERT */

10 中的其他函数

1 memcmp 函数

c primer plus 专题16:C预处理器_第19张图片

2 memcpy 函数

c primer plus 专题16:C预处理器_第20张图片

3 memset 函数

c primer plus 专题16:C预处理器_第21张图片

这个函数相当有用,可以将一块内存清零或置一,如下所示:

#include 
#include 

#define SIZE	50

int main(void)
{
	int data[SIZE];

	memset(data, 0, sizeof(int) * SIZE);		// 内存清 0
	memset(data, 0XFF, sizeof(int) * SIZE);		// 内存置 1

	return 0;
}

当执行内存清零时,整个数组如下所示:

c primer plus 专题16:C预处理器_第22张图片

当执行内存置一时,整个数组如下所示:

c primer plus 专题16:C预处理器_第23张图片

 

 

你可能感兴趣的:(C,Primer,Plus)