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

1 翻译程序的第一步

2 重新定义宏

3 带参数宏

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

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

执行流程:

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

6 变参宏(... 和 __VA_ARGS__)

#include <stdio.h>

/* 按照 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 指令  取消宏定义

2 条件编译

2.1 #ifdef    #else    #endif

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

3 #if    #else    #endif

defined 预处理运算符

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

#include <stdio.h>

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

9 断言 assert

C语言提供了断言标准库,#include <assert.h>

下面是标准库 <assert.h> 的说明:

#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

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 <string.g> 中的其他函数

1 memcmp 函数

2 memcpy 函数

3 memset 函数

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

#include <stdio.h>
#include <string.h>

#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;
}

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

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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值