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

news2025/1/23 11:54:15

目录

一、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 0
    a = 1;
    #endif
    
    printf("%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.coloradmin.cn/o/1268411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

投资者要不要更换黄金代理?

有一些投资者会问&#xff0c;要不要更换自己的黄金代理&#xff1f;笔者认为&#xff0c;换代理这个问题有一些东西需要关注。因此&#xff0c;我们今天就来讨论一下投资者该不该更改代理&#xff1f;如果要换&#xff0c;新的代理如何选择&#xff1f; 其实很简单&#xff0c…

数据结构-构造哈夫曼树【详解+代码+图示】一文解惑!

哈夫曼树 (Huffman Tree) 文章目录 哈夫曼树 (Huffman Tree)导论构造哈夫曼树语言描绘图形化理解 证明结论代码实现测试结果对照总结 导论 我们在学习哈夫曼树之前需要先了解 什么是哈夫曼树? 哈夫曼树 是一种最优树,是一类带权路径长度最短的二叉树,通过哈夫曼算法可以构建一…

虚幻学习笔记7—蓝图接口

一、前言 蓝图接口就是可以在蓝图中实现的接口&#xff0c;有它方便的地方&#xff0c;可以很方便的调用到实现了接口的函数。 二、实现 2.1、创建一个蓝图接口 1&#xff09;可以添加多个函数。 2&#xff09;函数在蓝图接口中只能规定输入和输出参数。 只有输入参数的可以…

Vue3生命周期函数(简述题)

1.图示 2.说明 3.补充 1.在vue3组合式API中&#xff0c;我们需要将生命周期函数先导入&#xff0c;然后才能使用。 import {onMounted} from vue2.beforeCreate和created被setup()方法所代替

Revit导出3D模型插件【GLTF|OBJ|DAE|STL|PLY|OFF|XYZ】

3dconvert_for_revit插件是NSDT 3DConvert工具集中的一种&#xff0c;可以快速将Revit模型导出为8种目标格式&#xff1a;GLTF、OBJ、GLB、DAE、STL、OFF、XYZ和PLY。 用户在进行格式转换之前&#xff0c;需要先下载安装对应Revit版本的插件。 NSDT在线工具推荐&#xff1a; T…

RabbitMQ消息模型之发布订阅Publish-Subscribe

发布订阅模型 Publish/Subscribe 发布订阅模型也称为广播模型&#xff0c;交换机类型需要指定为Fanout&#xff0c;正如从名称中猜到的那样&#xff0c;它是将接收到的所有消息广播到它知道的所有队列中。每个消费者都监听自己的队列&#xff0c;所以同一个消息&#xff0c;会…

多模块项目打包部署

目录结构 这些模块间相互依赖&#xff0c;打包的时候打父模块&#xff0c;就是带root的这个 先clean&#xff0c;再package&#xff0c;就跟一般的项目一样了。 有可能遇到报错Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test&#xff…

[Java]JUC并发编程

JUC并发编程 一、什么是JUC 使用到 java.util 工具包、包、分类 二、线程和进程 进程&#xff1a;一个正在运行的程序&#xff0c;QQ.exe Music.exe 程序的集合&#xff1b; 一个进程往往可以包含多个线程&#xff0c;至少包含一个&#xff01; Java默认有两个线程&#x…

微服务链路追踪组件SkyWalking实战

概述 微服务调用存在的问题 串联调用链路&#xff0c;快速定位问题&#xff1b;理清服务之间的依赖关系&#xff1b;微服务接口性能分析&#xff1b;业务流程调用处理顺序&#xff1b; 全链路追踪&#xff1a;对请求源头到底层服务的调用链路中间的所有环节进行监控。 链路…

短 URL 生成器设计:百亿短 URL 怎样做到无冲突?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 我们先来看看&#xff0c;当高并发遇到海量数据处理时的架构。在社交媒体上&#xff0c;人们经常需要分享一些 URL&#xff0c;但是有些 URL 可能会很长&#xff0c;比如&#xff1a; https://time.geekbang.org/hyb…

C#图像处理OpenCV开发指南(CVStar,03)——基于.NET 6的图像处理桌面程序开发实践第一步

1 Visual Studio 2022 开发基于.NET 6的OpenCV桌面程序 1.1 为什么选择.NET 6开发桌面应用&#xff1f; 选择 .NET 6&#xff08;最早称为 .NET Core&#xff09;而非 Frameworks.NET 的理由是&#xff1a;&#xff08;1&#xff09;跨平台&#xff1b;已经支持Windows,Linux…

PyQt基础_008_ 按钮类控件QSpinbox

基本操作 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class spindemo(QWidget):def __init__(self, parentNone):super(spindemo, self).__init__(parent)self.setWindowTitle("SpinBox 例子")self.resize(300,…

错误 LNK2001 无法解析的外部符号 __imp__CrtDbgReport

”属性“ -->”设置“ --> ”c“ – > ”代码生成“ --> ”运行库“ &#xff0c;将 ”多线程(MT)“ 改为 ”多线程(MTD)“。

JavaScript包装类型

前端面试大全JavaScript包装类型 &#x1f31f;经典真题 &#x1f31f;包装类型 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 是否了解 JavaScript 中的包装类型&#xff1f; &#x1f31f;包装类型 在 ES 中&#xff0c;数据的分类分为基本数据类型…

NCo3.1(08) - Nco3 服务器端编程

本篇博文不再重复ABAP调用外部服务器的基础&#xff0c;只介绍 NCo3 开发的过程和要点。需要了解相关知识点的小伙伴们自行参考&#xff1a; SAP接口编程 之JCo3.0系列(06) - Jco服务器端编程 PyRFC 服务器端编程要点 创建项目 新建一个 Console 项目&#xff0c;选择 .Net …

第一个C代码讲解

文章目录 编写C文件创建文本文件编写代码修改文件后缀切换文件路径 编译代码打开命令行使用gcc编译代码运行程序双击运行使用命令行运行 代码分析编译过程 编写C文件 编辑C代码文件的工具有很多&#xff0c;为了让大家初学的时候摆脱编译软件的干扰&#xff0c;更容易理解编译过…

数据结构 -- 并查集与图

目录 1.并查集 1.结构 2.原理 3.代码实现 1.存储 2.寻找根节点 3.是否为同一集合 4.求集合个数 5.合并为同一集合中 整体代码 2.图 1.基本知识 1.各个属性 2.特殊名词 3.图的解释 2.图的表示 1.邻接矩阵 2.邻接表 3.图的遍历 1.BFS--广度优先遍历 2.DFS--…

Python with提前退出:坑与解决方案

Python with提前退出&#xff1a;坑与解决方案 问题的起源 早些时候使用with实现了一版全局进程锁&#xff0c;希望实现以下效果&#xff1a; Python with提前退出&#xff1a;坑与解决方案 全局进程锁本身不用多说&#xff0c;大部分都依靠外部的缓存来实现的&#xff0c;r…

python读取excel自动化生成sql建表语句和java实体类字段

1、首先准备一个excel文件&#xff1a; idtypenameidint学号namestring姓名ageint年龄sexstring性别weightdecimal(20,4)体重scoredecimal(20,4)分数 2、直接生成java字段和注释&#xff1a; import pandas as pddf pd.read_excel(test.xlsx, sheet_nameSheet1)for i in ran…

k8s中批量处理Pod应用的Job和CronJob控制器介绍

目录 一.Job控制器 1.简介 2.Jobs较完整解释 3.示例演示 4.注意&#xff1a;如上例的话&#xff0c;执行“kubectl delete -f myJob.yaml”就可以将job删掉 二.CronJob&#xff08;简写为cj&#xff09; 1.简介 2.CronJob较完整解释 3.案例演示 4.如上例的话&#xf…