C语言中的一些关键字

volatile关键字

volatile关键字以前用的很少,但是在进行nRF51822定时器编程时,碰到在如下程序段,结合程序分析volatile关键字的作用。
#include "nrf51.h"
#include "nrf_gpio.h"
#include "led.h"
#include "time.h"
#include <stdbool.h>
#include <stdint.h>



/**
 * @brief Function for timer initialization.
 */
static volatile NRF_TIMER_Type * timer_init(timer_t timer)
{
    volatile NRF_TIMER_Type * p_timer;

    // 开始16 MHz晶振.
    NRF_CLOCK->EVENTS_HFCLKSTARTED  = 0;
    NRF_CLOCK->TASKS_HFCLKSTART     = 1;

    // 等待外部振荡器启动
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) 
    {
        // Do nothing.
    }

    switch (timer)
    {
        case TIMER0:
            p_timer = NRF_TIMER0;
            break;

        case TIMER1:
            p_timer = NRF_TIMER1;
            break;

        case TIMER2:
            p_timer = NRF_TIMER2;
            break;

        default:
            p_timer = 0;
            break;
    }
    return p_timer;
}


/** @brief Function for using the peripheral hardware timers to generate an event after requested number of milliseconds.
 *
 * @param[in] timer Timer to be used for delay, values from @ref p_timer
 * @param[in] number_of_ms Number of milliseconds the timer will count.
 * @note This function will power ON the requested timer, wait until the delay, and then power OFF that timer.
 */

void nrf_timer_delay_ms(timer_t timer, uint_fast16_t volatile number_of_ms)
{
    volatile NRF_TIMER_Type * p_timer = timer_init(timer);

    if (p_timer == 0) 
    {
        while(true) 
        {
            // Do nothing.
        }
    }

    p_timer->MODE           = TIMER_MODE_MODE_Timer;        // 设置为定时器模式
    p_timer->PRESCALER      = 9;                            // Prescaler 9 produces 31250 Hz timer frequency => 1 tick = 32 us.
    p_timer->BITMODE        = TIMER_BITMODE_BITMODE_16Bit;  // 16 bit 模式.
    p_timer->TASKS_CLEAR    = 1;                            // 清定时器.
    
    // With 32 us ticks, we need to multiply by 31.25 to get milliseconds.
    p_timer->CC[0]          = number_of_ms * 31;
    p_timer->CC[0]         += number_of_ms / 4; 
    p_timer->TASKS_START    = 1;                    // Start timer.

    while (p_timer->EVENTS_COMPARE[0] == 0)
    {
        // Do nothing.
    }

    p_timer->EVENTS_COMPARE[0]  = 0;
    p_timer->TASKS_STOP         = 1;                // Stop timer.
}
/** @} */


在分析程序之前,先来介绍一下volatile关键字。在这里是根据《C语言深度解剖》一书的理解来写的。
volatile本身的意思就是易变的、不稳定的意思。而C语言在编译的时候往往会对程序进行优化,但是对一些特殊的地址进行优化可能会得到适得其反的效果(在这里仅仅是自己得到的理论,还没有验证与碰到过)。因此,在遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。下面是关于volatile关键字对比的两个例子。
int i=10;
int j=i;		//1语句
int k=i;		//2语句
此时编译器对代码进行优化,由于1语句和2语句之间变量i并没有被赋值,也就是i的值没有发生改变,所以编译器在1语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在2语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值,这样提高了效率。
另一个例子:
volatile int i=10;
int j=i;		//3语句
int k=i;		//4语句
此时,volatile告诉编译器,i是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。
如果i是一个寄存器变量,表示一个端口数据或者是多个线程共享数据,那么就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

总结:  volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

简单来说,就是自己所定义的变量在程序运行过程中一直会变,如果希望这个值被正确处理,就需要每次从内存中去读这个值,这样就不会有错误了,volatile关键字就是这个作用。
一般来说,volatile关键字用在如下的几个地方:
1、中断服务程序中修改的供其他程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因此每次对它的读写都可能有不同意义。


了解了这么多关于volatile关键字的知识以及用法,现在来分析nRF51822定时器程序。
在nRF51822中,用volatile这个类型修饰符来修饰NRF_TIMER_TYPE *p_timer这个指向函数的指针变量,也就是说明这个指针变量是易变的,编译器在访问该变量的时候不再进行优化,而是直接从变量地址中读取数据。
在此,对程序按照运行流程进行分析。当主函数这样调用函数nrf_timer_delay_ms(TIMER0,TIMER_DELAY_MS)(TIMER_DELAY_MS为在头文件中的宏定义,为1000UL)时,程序进入子函数中。在此个人感觉子函数形参变量number_of_ms用volatile修饰符修饰没用,因为TIMER_DELAY_MS本来就为一 宏定义变量 ,并不会在中断程序中或者上边说的其他情况下进行改变。而p_timer这个指针变量用volatile修饰符来修饰,可能是为了避免其他可能产生的情况使其发生变化,但是总的来说感觉也非必须。 有待删掉之后进行验证。        

static关键字

首先说一下static关键字的三个明显的作用:
1、在函数体中,一个被声明为静态的变量在这一函数被调用过程中维持其值不变(该变量存放在静态变量去)
2、在模块内(但是在函数外),一个被声明为静态的变量可以被模块内所用的函数访问,但是不能被模块外其他函数访问,它是一个 本地的全局变量
3、在模块内,一个被声明为静态的函数只可被这一模块内的其他函数使用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

extern关键字



























































  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要遍历C语言关键字,可以使用C语言标准库的<string.h>头文件和<ctype.h>头文件的函数。下面是一种实现方式: 1. 定义一个字符数组来存储C语言的所有关键字,例如: ``` char *keywords[] = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"}; ``` 2. 对于输入的每个单词,使用C语言标准库的<ctype.h>头文件的函数检查它是否为关键字。例如,使用strcmp函数比较输入的单词是否与数组的任何一个关键字相等: ``` int is_keyword(char *word) { int i, n; n = sizeof(keywords) / sizeof(char *); for (i = 0; i < n; i++) { if (strcmp(word, keywords[i]) == 0) { return 1; } } return 0; } ``` 3. 对于输入的每个单词,还需要使用C语言标准库的<ctype.h>头文件的函数将其转换为小写字母,以便与关键字数组的字符串进行比较。例如,使用tolower函数将单词转换为小写字母: ``` void to_lower(char *word) { while (*word) { *word = tolower(*word); word++; } } ``` 4. 最后,可以将输入的文本分解成单词,并调用is_keyword函数和to_lower函数来检查它们是否为关键字。 以下是一个完整的示例程序,演示如何遍历C语言关键字: ``` #include <stdio.h> #include <string.h> #include <ctype.h> char *keywords[] = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"}; int is_keyword(char *word) { int i, n; n = sizeof(keywords) / sizeof(char *); for (i = 0; i < n; i++) { if (strcmp(word, keywords[i]) == 0) { return 1; } } return 0; } void to_lower(char *word) { while (*word) { *word = tolower(*word); word++; } } int main() { char text[] = "for (int i = 0; i < n; i++) { printf(\"%d\\n\", i); }"; char *word; word = strtok(text, " "); ### 回答2: 在C语言关键字是预定义的标识符,用于表示语言的特殊功能和结构。要遍历C语言关键字,可以按照以下步骤进行: 1. 创建包含C语言所有关键字的数组。根据C语言的标准,可以将关键字存储在一个字符串数组。 2. 使用循环结构,遍历数组的每个关键字。可以使用for循环或while循环来实现遍历。 3. 在循环,将每个关键字打印出来或进行其他操作。可以使用printf函数将关键字输出到控制台上,也可以将其存储在新的数组或其他数据结构。 4. 执行完循环后,即可遍历所有的C语言关键字。 下面是一个简单的示例代码,用于遍历C语言关键字: ```c #include<stdio.h> #include<string.h> int main() { char* keywords[] = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"}; int numKeywords = sizeof(keywords) / sizeof(keywords[0]); for(int i = 0; i < numKeywords; i++) { printf("%s\n", keywords[i]); } return 0; } ``` 以上代码通过使用循环遍历并打印出C语言的所有关键字。运行代码后,会依次打印出每个关键字,完成关键字的遍历。 ### 回答3: 要遍历C语言关键字,首先需要了解C语言关键字有哪些。C语言关键字是由编译器预先定义的,用于表示特定功能或命令的保留字。 C语言关键字共有32个,包括基本数据类型(如int、float、char等)、流程控制语句(如if、while、for等)、函数定义关键字(如void、return等)等。 遍历C语言关键字可以采用以下步骤: 1. 定义一个字符串数组,用于存储C语言关键字。 2. 创建一个循环,循环变量从0到31(因为C语言一共有32个关键字)。 3. 在循环,依次将每个关键字赋值给字符串数组的元素。 4. 遍历完所有关键字后,输出或处理字符串数组关键字。 以下是示例代码: ``` #include <stdio.h> #include <string.h> int main() { char keywords[32][10] = {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"}; int i; for (i = 0; i < 32; i++) { printf("%s\n", keywords[i]); } return 0; } ``` 以上代码会将C语言关键字遍历并逐个输出。可以根据实际需求,将关键字存储到其他数据结构,或进行其他处理操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值