C语言基础--#if与#endif

目录

一、C语言中的 #if()和 #end if 用法

1.   #if 表达式 + 程序段 + #endif  形式 

2.   #ifdef标示符 + 标识符 +  #endif  形式

3. #if   0/  #if 1     +    #endif  形式

  4.  \可用于一行的结尾,表示本行与下一行连接起来

二、xTaskCreate函数

三、指针相关

 1. 解引用

​编辑2. 野指针

 3.两个指针相减

4.数组通过指针来访问

5.结构体传参与打印:


一、C语言中的 #if()和 #end if 用法

C语言中的 #if()和 #end if 用法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_24096023/article/details/85253645

1.   #if 表达式 + 程序段 + #endif  形式 

#if 表达式程序段1#else程序段2#endif表示:如果表达式为真,则编译程序段1,否则编译程序段2

2.   #ifdef标示符 + 标识符 +  #endif  形式

表示:如果标示符已经被#define命令定义过,则编译程序段。 eg:

#define a 100 
此时,我们要检查a是否定义(假设我们已经记不着这点了),或者我们要给a一个不同的值,就加入如下句子 
#if defined a 
#undef a 
#define a 200 
#endif 
上述语句检验a是否被定义,如果被定义,则用#undef语句解除定义,并重新定义a为200 

3. #if   0/  #if 1     +    #endif  形式

        首先这里的0和1可以当做普通表达式来看待,1为真,0为假。

        其次使用#if 0 有个很实用的方法就是当做注释来用。 有时候比用 // 和 /*..........*/ 整洁美观

        比如用在调试代码的时候,code中定义的是一些调试版本的代码,此时code完全被编译器忽略。如果想让code生效,只需把#if 0改成#if 1

eg:

#include <iostream>int main(void)
{int a = 0;#if 0a = 1;#endifprintf("%d\n",a);return 0;
}

  4.  \可用于一行的结尾,表示本行与下一行连接起来

        C语言中以 ; 作为语句的结束,不以行为单位结束,当一行的内容太长不方便卸载一行时可使用反斜杠"\"作为继续符,分为多行书写

例如:STM32官方库文件"stm32f30x_usart.h"有如下一段:
#define IS_USART_123_PERIPH(PERIPH) (((PERIPH) == USART1) || \
                                     ((PERIPH) == USART2) || \
                                     ((PERIPH) == USART3))
写成一行意义完全相同:

#define IS_USART_123_PERIPH(PERIPH) (((PERIPH) == USART1) || ((PERIPH) == USART2) || ((PERIPH) == USART3

C语言中反斜杠"\"的意义和用法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Wind4study/article/details/43502255

二、xTaskCreate函数

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务

参数描述:
pvTaskCode
        函数指针,可以简单地认为任务就是一个C函数。
        它稍微特殊一点:永远不退出,或者退出时要调用"vTaskDelete(NULL)"
pcName
        任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。
        长度为:configMAX_TASK_NAME_LEN
usStackDepth
        每个任务都有自己的栈,这里指定栈大小。
        单位是word,比如传入100,表示栈大小为100 word,也就是400字节。
        最大值为uint16_t的最大值。
        怎么确定栈的大小,并不容易,很多时候是估计。
        精确的办法是看反汇编码。
pvParameters

        调用pvTaskCode函数指针时用到:pvTaskCode(pvParameters)
uxPriority
        优先级范围:0~(configMAX_PRIORITIES – 1)
        数值越小优先级越低,:更高优先级的、或者后面创建的任务先运行。
        如果传入过大的值,xTaskCreate会把它调整为(configMAX_PRIORITIES – 1)
pxCreatedTask
        用来保存xTaskCreate的输出结果:task handle。
        以后如果想操作这个任务,比如修改它的优先级,就需要这个handle。
        如果不想使用该handle,可以传入NULL。
返回值
        成功:pdPASS;
        失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只有内存不足)
        注意:返回值是pdFAIL不对。
        pdFAIL是0,errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY是-1。

多个任务可以使用同一个函数;

void vTaskFunction( void *pvParameters )
{const char *pcTaskText = pvParameters;volatile uint32_t ul; /* volatile用来避免被优化掉 *//* 任务函数的主体一般都是无限循环 */for( ;; ){/* 打印任务的信息 */printf(pcTaskText);/* 延迟一会(比较简单粗暴) */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ){}}
}
static const char *pcTextForTask1 = "T1 run\r\n";
static const char *pcTextForTask2 = "T2 run\r\n";
int main( void )
{prvSetupHardware();xTaskCreate(vTaskFunction, "Task 1", 1000, (void *)pcTextForTask1, 1, NULL);xTaskCreate(vTaskFunction, "Task 2", 1000, (void *)pcTextForTask2, 1, NULL);/* 启动调度器 */vTaskStartScheduler();/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}
char* a = "good";
char b[20] = "good";

        a是指向第一个字符’g’的指针
        b是指向字符数组第一个元素’g’的指针
        二者看似相同,然而并非如此

字符串常量是放在常量区的,只可读。而字符数组是存在于栈中的,可以修改其数据
因此:
char* a = “helloworld”; “helloworld”是存放于常量区,因此只可读不可写
char a[20] = “helloworld”; “helloworld”存在于栈内,可读可写char a[20] = “helloworld”;由于存放于栈中,因此读取速度比char* a = “helloworld”快char * a = “helloworld”在编译时便已经确定了值
char a[20] = “helloworld”则是在运行时确定的当执行char a[] = “helloworld”;时,系统将会分配11个字节的空间,最后一个字节存放’\0’,当调用strlen(a)时得到的值为10,因此strlen()不会将’\0’计算进去

        故上文pcTextForTask1和2就是指向'T'的指针,或者说将字符串的地址存放在该变量中,这个变量是一个指针变量。

        指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,所以不管你存储的是int指针、float指针、long指针,对于存储指针的内存来说都是分配同样大小的内存的,这也为使用void指针可以存储任意类型的指针打下了基础,但是注意在使用void指针,要将其强制转换为具体的指针类型。

不同类型的指针需要注意如下调试结果:

三、指针相关

 1. 解引用

注意: 这样能存下a的地址,虽然指针类型不同。

但是通过修改只能修改第一个字节:

他们主要的不同是地址+1,跳过的地址也不同:

         指针类型决定了指针+1操作的时候,跳过了几个字节,即决定了指针的步长。

注意:pa的大小与a的大小无关:

2. 野指针

(a是局部变量,p虽然能接收a的地址,但是a除了作用域销毁了,p变成野指针)

         虽然还能打印出来,但是他与可能不是10,因为地址还在,只是有可能会被占用。只是这块空间不属于我的程序了,还给了操作系统,我只是没有当前空间的使用权限,但是这块内存空间还在。

 

 3.两个指针相减

4.数组通过指针来访问

5.结构体传参与打印:

         如果不传递地址,会在内存中再开辟一个大小相同的空间,造成空间和时间的浪费,而传地址只会开辟大小是4/8个字节的空间,通过指针所指向的空间来打印。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/231362.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个具有电子杂志的模板平台,制作起来事半功倍!

平时大家都是怎么做电子杂志的呢&#xff1f;用什么软件来做呢&#xff1f;现在&#xff0c;越来越多的企业开始将传统的纸质杂志转变为电子杂志。电子杂志不仅可以节省印刷成本&#xff0c;还能为读者提供更加丰富的阅读体验。那么&#xff0c;如何快速制作电子杂志呢&#xf…

【Android Jetpack】Room数据库

文章目录 引入EntitiesPrimary Key主键索引和唯一性对象之间的关系外键获取关联的Entity对象嵌套对象Data Access Objects&#xff08;DAOs&#xff09;使用Query注解的方法简单的查询带参数查询返回列的子集可被观察的查询 数据库迁移用法 引入 原始的SQLite有以下两个缺点: …

【刷题】DFS

DFS 递归&#xff1a; 1.判断是否失败终止 2.判断是否成功终止&#xff0c;如果成功的&#xff0c;记录一个成果 3.遍历各种选择&#xff0c;在这部分可以进行剪枝 4.在每种情况下进行DFS&#xff0c;并进行回退。 199. 二叉树的右视图 给定一个二叉树的 根节点 root&#x…

Cytoscape软件下载、安装、插件学习[基础教程]

写在前面 今天分享的内容是自己遇到问题后&#xff0c;咨询社群里面的同学&#xff0c;帮忙解决的总结。 关于Cytoscape&#xff0c;对于做组学或生物信息学的同学基本是陌生的&#xff0c;可能有的同学用这个软件作图是非常溜的&#xff0c;做出来的网络图也是十分的好看&am…

(亲测有效)解决windows11无法使用1500000波特率的问题

大家好&#xff01;我是编码小哥&#xff0c;欢迎关注&#xff0c;持续分享更多实用的编程经验和开发技巧&#xff0c;共同进步。 1、问题描述 从图1可以看出串口是正常的&#xff0c;安装的驱动是CP210xVCPInstaller_x64.exe&#xff0c;但是从图2可以看出&#xff0c;串口拒…

Java数据结构之《顺序查找》问题

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等偏下的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题只要我…

解决:ValueError: must have exactly one of create/read/write/append mode

解决&#xff1a;ValueError: must have exactly one of create/read/write/append mode 文章目录 解决&#xff1a;ValueError: must have exactly one of create/read/write/append mode背景报错问题报错翻译报错位置代码报错原因解决方法今天的分享就到此结束了 背景 在使用…

【存储】blotdb的原理及实现(2)

【存储】etcd的存储是如何实现的(3)-blotdb 在etcd系列中&#xff0c;我们对作为etcd底层kv存储的boltdb进行了比较全面的介绍。但是还有两个点没有涉及。 第一点是boltdb如何和磁盘文件交互。 持久化存储和我们一般业务应用程序的最大区别就是其强依赖磁盘文件。一方面文件数…

基于springboot+vue的在线考试系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

顺丰JAVA开发一面—面试实战经验分析【已通过】

文章目录 面试总结面试开始项目相关基础知识反问环节 顺丰JAVA开发一面面试过程中的问题确实涵盖了很多方面&#xff0c;从项目架构到基础知识再到具体技术细节都有所涉及。 面试官的提问风格也是比较开放的&#xff0c;注重考察面试者的深度理解和解决问题的能力。以下是对每个…

AI模型训练——入门篇(一)

前言 一文了解NLP&#xff0c;并搭建一个简单的Transformers模型&#xff08;含环境配置&#xff09; 一、HuggingFace 与NLP 自从ChatGPT3 问世以来的普及性使用&#xff0c;大家或许才真正觉察AI离我们已经越来越近了&#xff0c;自那之后大家也渐渐的开始接触stable diff…

【开源】基于Vue.js的大病保险管理系统的设计和实现

项目编号&#xff1a; S 031 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S031&#xff0c;文末获取源码。} 项目编号&#xff1a;S031&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大…