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 
 
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. 解引用

C语言基础--#if与#endif_第1张图片

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

C语言基础--#if与#endif_第2张图片

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

C语言基础--#if与#endif_第3张图片

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

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

C语言基础--#if与#endif_第4张图片

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

C语言基础--#if与#endif_第5张图片2. 野指针

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

C语言基础--#if与#endif_第6张图片

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

C语言基础--#if与#endif_第7张图片

 3.两个指针相减

C语言基础--#if与#endif_第8张图片

C语言基础--#if与#endif_第9张图片

4.数组通过指针来访问

C语言基础--#if与#endif_第10张图片

C语言基础--#if与#endif_第11张图片

C语言基础--#if与#endif_第12张图片

5.结构体传参与打印:

C语言基础--#if与#endif_第13张图片

C语言基础--#if与#endif_第14张图片         如果不传递地址,会在内存中再开辟一个大小相同的空间,造成空间和时间的浪费,而传地址只会开辟大小是4/8个字节的空间,通过指针所指向的空间来打印。

你可能感兴趣的:(51单片机,开发语言,c语言,stm32)