前言
本文的小知识点是C语言的三目运算符,这是一个很好用的运算符,你可以看到在kinetis的库函数里有大量的应用,本篇我会用一个我们熟悉的例子进行讲解。
知识点
? :
也称为条件运算符号,是C语言中唯一的一个三目运算符,结合顺序是从右往左。
条件运算符的优先级比较低,只比赋值运算符和逗号运算符高。
实例分析
例1:
这是qn908的时钟分配图:
从上图可以看出sysclk的来源有三个,这在CLK_CTRL寄存器中可以清楚的看到,如下图:
那kinetis的时钟库函数是如何处理的呢。请看下面的程序,三目运算符的完美应用。
fsl_clock.c
#define getSysconClkMux() ((SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK) >> SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT)
static uint32_t CLOCK_GetCoreSysClkFreq(void)
{
return (getSysconClkMux() == 0) ? CLOCK_GetRco32MFreq() : (getSysconClkMux() == 1) ?
CLOCK_GetXinFreq() :
(getSysconClkMux() == 2) ? CLOCK_Get32KFreq() : 0;
}
记住结合顺序是从右往左,那就从右向左慢慢分析。
a.
(getSysconClkMux() == 2) ? CLOCK_Get32KFreq() : 0;
getSysconClkMux这个宏的作用就是得到CLK_CTRL寄存器的SYS_CLK_SEL位域的值。
所以上面这条语句的意思就是,如果这个位域值为2,就返回32K时钟的频率值,这和上面的寄存器里的表达一致。
b.
(getSysconClkMux() == 1) ?CLOCK_GetXinFreq() :
(getSysconClkMux() == 2) ? CLOCK_Get32KFreq() : 0;
同理,位域为1,返回外部时钟的频率值.
c.
(getSysconClkMux() == 0) ? CLOCK_GetRco32MFreq() :
(getSysconClkMux() == 1) ? CLOCK_GetXinFreq() :
(getSysconClkMux() == 2) ? CLOCK_Get32KFreq() : 0;
同理,位域为0,返回RCO的32M的频率值.
也就是getSysconClkMux每一个值的情况对应一种返回值。是不是突然想到switch case语句了。
switch(getSysconClkMux() )
{
case 0: return CLOCK_GetRco32MFreq();
case 1: return CLOCK_GetXinFreq() ;
case 2: return CLOCK_Get32KFreq();
default: return 0;
}
三目的明显好处就是一条语句搞定,直接return。
例2:
fsl_clock.c
static uint32_t CLOCK_GetRco32MFreq(void)
{
return (SYSCON->CLK_CTRL & SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK) ? CLK_OSC_32MHZ / 2 : CLK_OSC_32MHZ;
}
从上面的表达式可以看出,条件运算符比除法运算符优先级低。
总结
三目运算符也可以实现switch case语句的功能,而且更简洁。
结合顺序是从右往左。
C语言中唯一的一个三目运算符。
优先级只比赋值运算符和逗号运算符高。