RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

嵌入式C語(yǔ)言的一些高階知識(shí)

Dp1040 ? 來(lái)源:玩點(diǎn)嵌入式 ? 2023-06-29 09:19 ? 次閱讀

此系列文章,于振南老師向大家講述嵌入式C語(yǔ)言的一些高階知識(shí),俗稱“騷操作”,助你水平再上一個(gè)臺(tái)階!

C語(yǔ)言,是一門非常靈活而強(qiáng)大的編程語(yǔ)言。同樣一個(gè)算法、一個(gè)功能,我們可以把它寫得中規(guī)中矩,也可以把它寫得晦澀難懂。而且很多自詡為編程高手的人,偏偏就喜歡把程序?qū)懗商鞎?,認(rèn)為讓別人看不懂,卻能實(shí)現(xiàn)正確的功能,此乃技術(shù)高超的表現(xiàn)。

我不評(píng)價(jià)這樣的作法是否可取,因?yàn)槊總€(gè)人都有各自的風(fēng)格和個(gè)性。讓他違背意愿去編程,那么編程可能就會(huì)變得索然無(wú)味,毫無(wú)樂(lè)趣。很多時(shí)候不是我們想把程序?qū)懙秒y懂,而是我們要去看懂別人的程序。 在本文中,振南列舉一些我曾經(jīng)見過(guò)和使用過(guò)的編程技巧,并進(jìn)行深入的解析。

一、字符串的實(shí)質(zhì)就是指針

字符串是C語(yǔ)言中最基礎(chǔ)的概念,也是最常被用到的。在嵌入式開發(fā)中,我們經(jīng)常要將一些字符串通過(guò)串口顯示到串口助手或調(diào)試終端上,作為信息提示,以便讓我們了解程序的運(yùn)行情況;或者是將一些常量的值轉(zhuǎn)為字符串,來(lái)顯示到液晶等顯示設(shè)備上。 那么,C語(yǔ)言中的字符串到底是什么?其實(shí)字符串本身就是一個(gè)指針,它的值(即指針?biāo)赶虻牡刂罚┚褪亲址鬃址牡刂贰?為了解釋這個(gè)問(wèn)題,我經(jīng)常會(huì)舉這樣一個(gè)例子:如何將一個(gè)數(shù)值轉(zhuǎn)化為相應(yīng)的16進(jìn)制字符串。比如,把100轉(zhuǎn)為”0X64”。 我們可以寫這樣一個(gè)函數(shù):

void Value2String(unsigned char value,char *str)
{

char *Hex_Char_Table="0123456789ABCDEF";

str[0] = '0';
str[1] = 'X';
str[4] = 0;

str[2]=Hex_Char_Table[value>>4];

str[3]=Hex_Char_Table[value&0X0F];
}

字符串常量實(shí)質(zhì)是內(nèi)存中的字節(jié)序列,如下圖所示:

ad31c730-1614-11ee-962d-dac502259ad0.jpg 上面,振南說(shuō)“字符串本身就是指針”,那么見證這句話真正意義的時(shí)刻來(lái)了,我們將上面程序進(jìn)行簡(jiǎn)化:

void Value2String(unsigned char value,char *str)
{

str[0]='0';str[1]='X';str[4]=0;

str[2]="0123456789ABCDEF"[value>>4];

str[3]="0123456789ABCDEF"[value&0X0F];
}

Hex_Char_Table 這個(gè)指針變量其實(shí)是多余的,“字符串本身就是指針”,所以它后面可以直接用 [] 配合下標(biāo)來(lái)取出其中的字符。凡是實(shí)質(zhì)上為指針類型(即表達(dá)的是地址意義)的變量或常量,都可以直接用[]或*來(lái)訪問(wèn)它所指向的數(shù)據(jù)序列中的數(shù)據(jù)元素。

二、轉(zhuǎn)義符

C語(yǔ)言中要表達(dá)一個(gè)字節(jié)數(shù)據(jù)序列(內(nèi)存中連續(xù)存儲(chǔ)的若干個(gè)字節(jié)),我們可以使用字節(jié)數(shù)組,比如unsigned char array[10]={0,1,2,3,4,5,6,7,8,9}。 其實(shí)字符串,本質(zhì)上也是一個(gè)字節(jié)序列,但是通常情況下它所存儲(chǔ)的字節(jié)的值均為 ASCII 中可打印字符的碼值,如’A’、’ ‘、’|’等。那在字符串中是否也可以出現(xiàn)其它的值呢?這樣,我們就可以用字符串的形式來(lái)表達(dá)一個(gè)字節(jié)序列了。很多時(shí)候,它可能比字節(jié)數(shù)組要方便一些。字符串中的轉(zhuǎn)義符就是用來(lái)干這個(gè)的。請(qǐng)看如下程序:

const unsigned char array[10]={0,1,2,3,4,5,6,7,8,9};

char *array="x00x01x02x03x04x05x06x07x08x09";
這兩種寫法,array所指向的內(nèi)存字節(jié)序列是基本一樣的(后者最后還有一個(gè)0)。當(dāng)然,如果我們把a(bǔ)rray傳到strlen去計(jì)算長(zhǎng)度,返回的值為0。因?yàn)樗谝粋€(gè)字節(jié)的值為0。但是我們?nèi)匀豢梢允褂胊rray[n]的方式去訪問(wèn)序列中的數(shù)據(jù)。
char *str="ABCDEFG";

char *str="x41x42x43x44x45x46x47";

上面程序中的兩種寫法,是完成等價(jià)的。

字符串中的轉(zhuǎn)義符的目的是為了在本應(yīng)該只能看到ASCII可打印字符的序列中,可以表達(dá)其它數(shù)值或特殊字符。如經(jīng)常使用的回車換行” ”,其實(shí)質(zhì)就是”x0dx0a”;通常我們所說(shuō)的字符串結(jié)束符?,其實(shí)就是0的八進(jìn)制轉(zhuǎn)義表達(dá)形式。

三、字符串常量的連接

在研讀一些開源軟件的源代碼時(shí),我見到了字符串常量的一個(gè)比較另類的用法,在這里介紹給大家。 有些時(shí)候,為了讓字符串常量?jī)?nèi)容層次更加清晰,就可以把一個(gè)長(zhǎng)字符串打散成若干個(gè)短字符串,它們順序首尾相接,在意義上與長(zhǎng)字符串是等價(jià)的。比如“0123456789ABCDEF”可以分解為“0123456789”“ABCDEF”,即多個(gè)字符串常量可以直接連接,夠成長(zhǎng)字符串。這種寫法,在 printf 打印調(diào)試信息的時(shí)候可能會(huì)更多用到。

printf("A:%d B:%d C:%d D:%d E:%d F:%d
",1,2,3,4,5,6);

printf("A:%d " 
 "B:%d " 
 "C:%d " 
 "D:%d " 
 "E:%d " 
 "F:%d
",1,2,3,4,5,6);
在 printf 的格式化串很長(zhǎng)的時(shí)候,我們把它合理的打散,分為多行,程序就會(huì)顯得更多工整。

四、長(zhǎng)字符串的拆分技巧

很多時(shí)候我們需要進(jìn)行長(zhǎng)字符串的拆分。問(wèn)題是如何實(shí)現(xiàn)它? 很多人可能都會(huì)想到使用那個(gè)分隔字符,比如空格、逗號(hào)。然后去一個(gè)個(gè)數(shù)要提取的參數(shù)前面有幾個(gè)分隔字符,然后后將相應(yīng)位置上的字符組成一個(gè)新的短字符串。如下圖所示: ad4dc796-1614-11ee-962d-dac502259ad0.jpg 這種方法固然可行,但是略顯笨拙。其實(shí),對(duì)于這種有明顯分隔符的長(zhǎng)字符串,我們可以采用“打散”或“爆炸”的思想,具體過(guò)程是這樣的:將長(zhǎng)字符串中的所有分隔符全部替換為’?’,即字符串結(jié)束符。此時(shí),長(zhǎng)字符串就被分解成了在內(nèi)存中順序存放的若干個(gè)短字符串。 如果要取出第n個(gè)短字符串,可以用這個(gè)函數(shù):

char * substr(char *str,n)
{
unsigned char len=strlen(str);

for(;len>0;len--) {if(str[len-1]==' ') str[len-1]=0;}

for(;n>0;n--)
{
str+=(strlen(str)+1);
}

return str;
}
很多時(shí)候我們需要一次性訪問(wèn)長(zhǎng)字符串中的多個(gè)短字符串,此時(shí)振南經(jīng)常會(huì)這樣來(lái)作:通過(guò)一個(gè)循環(huán),將長(zhǎng)字符串中的所有分隔符替換為’?’,在此過(guò)程中將每一個(gè)短字符串首字符的位置記錄到一個(gè)數(shù)組中,代碼如下:
unsigned char substr(unsigned char *pos,char *str)
{

unsigned char len=strlen(str);
unsigned char n=0,i=0;

for(;i
舉個(gè)例子:我們要提取”abc 1000 50 off 2500”中的”abc”、”50”和”off”,可以使用上面的函數(shù)來(lái)實(shí)現(xiàn)。
unsigned char pos[10];
char str[30];

strcpy(str,"abc 1000 50 off 2500");

substr(pos,str);
str+pos[0]; //"abc"
str+pos[2]; //"50"
str+pos[3]; //"off"

五、取出數(shù)值的各位數(shù)碼

在實(shí)際項(xiàng)目中,我們經(jīng)常需要提取一個(gè)數(shù)值的某些位的數(shù)碼,比如用數(shù)碼管來(lái)顯示數(shù)值或?qū)⒁粋€(gè)數(shù)值轉(zhuǎn)成字符串,都會(huì)涉及到這一操作。 那如何實(shí)現(xiàn)這一操作呢?雖然這個(gè)問(wèn)題看似很簡(jiǎn)單,但提出這一問(wèn)題的人還不在少數(shù)。 請(qǐng)看下面的函數(shù):

void getdigi(unsigned char *digi,unsigned int num)
{

digi[0]=(num/10000)%10;
digi[1]=(num/1000)%10;
digi[2]=(num/100)%10;
digi[3]=(num/10)%10;
digi[4]=num%10;
}
它的主要操作就是除法和取余。這個(gè)函數(shù)只是取出一個(gè)整型數(shù)各位的數(shù)碼,那浮點(diǎn)呢?

其實(shí)一樣的道理,請(qǐng)看下面函數(shù)(我們默認(rèn)整數(shù)與小數(shù)部分均取4位)。

void getdigi(unsigned char *digi1,unsigned char *digi2,unsigned float num)
{
unsigned int temp1=num;
unsigned int temp2=((num-temp1)*10000);

digi1[0]=(temp1/1000)%10;
digi1[1]=(temp1/100)%10;
digi1[2]=(temp1/10)%10;
digi1[3]=(temp1)%10;

digi2[0]=(temp2/1000)%10;
digi2[1]=(temp2/100)%10;
digi2[2]=(temp2/10)%10;
digi2[3]=(temp2)%10;
}
有人說(shuō),我更喜歡用sprintf函數(shù),直接將數(shù)值格式化打印到字符串里,各位數(shù)碼自然就得到了。
char digi[10];

sprintf(digi,"%d",num); //**整型

char digi[10];

sprintf(digi,"%f",num); //**浮點(diǎn)

沒(méi)問(wèn)題。但在嵌入式平臺(tái)上使用sprintf函數(shù),通常代價(jià)是較大的。

作為嵌入式工程師,一定要惜字如金,尤其是在硬件資源相對(duì)較為緊張的情況下。sprintf非常強(qiáng)大,我們只是一個(gè)簡(jiǎn)單的提取數(shù)值數(shù)碼或?qū)?shù)值轉(zhuǎn)為相應(yīng)的字符串的操作,使用它有些暴殄天物。這種時(shí)候,我通常選擇寫一個(gè)小函數(shù)或者宏來(lái)自己實(shí)現(xiàn)。

六、printf的實(shí)質(zhì)與使用技巧

printf是我們非常熟悉的一個(gè)入門級(jí)的標(biāo)準(zhǔn)庫(kù)函數(shù),每當(dāng)我們說(shuō)出計(jì)算機(jī)金句”Hello World!”時(shí),其實(shí)無(wú)意中就提到了它:printf(“hello world!”); 它可以某種特定的格式、進(jìn)制或形式輸出任何變量、常量和字符串,為我們提供了極大的方便,甚至成為了很多人調(diào)試程序時(shí)重要的Debug手段。但是在嵌入式中,我們就需要剖析一下它的實(shí)質(zhì)了。 printf 函數(shù)的底層是基于一個(gè) fputc 的函數(shù),它用于實(shí)現(xiàn)單個(gè)字符的具體輸出方式,比如是將字符顯示到顯示器上,或是存儲(chǔ)到某個(gè)數(shù)組中(類似sprintf),或者是通過(guò)串口發(fā)送出去,甚至不是串口,而是以太網(wǎng)、CANI2C接口。 以下是一個(gè)STM32項(xiàng)目中fputc函數(shù)的實(shí)現(xiàn):

int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);
{
USART1->DR = (u8) ch;
}

return ch;
}

fputc中將ch通過(guò)USART1發(fā)出。這樣,我們?cè)谡{(diào)用printf的時(shí)候,相應(yīng)的信息就會(huì)從USART1打印出來(lái)。

“上面你說(shuō)的這些,我都知道,有什么新鮮的!”確實(shí),通過(guò)串口打印信息是我們司空見慣的。 那么,下面的fputc你見過(guò)嗎?

int fputc(int ch, FILE *f)
{
LCD_DispChar(x,y,ch);
x++;
if(x>=X_MAX)
{
x=0;y++;

if(y>=Y_MAX)*
{
 y=0;
}
}
return ch;
}

這個(gè)fputc將字符顯示在了液晶上(同時(shí)維護(hù)了字符的顯示位置信息),這樣當(dāng)我們調(diào)用printf的時(shí)候,信息會(huì)直接顯示在液晶上。

說(shuō)白了,fputc 就是對(duì)數(shù)據(jù)進(jìn)行了定向輸出。這樣我們可以把 printf 變得更靈活,來(lái)應(yīng)對(duì)更多樣的應(yīng)用需求。 在振南經(jīng)歷的項(xiàng)目中,曾經(jīng)有過(guò)這樣的情況:單片機(jī)有多個(gè)串口,串口1用于打印調(diào)試信息,串口2與ESP8266 WIFI模塊通信,串口3與SIM800 GPRS模塊通信。3個(gè)串口都需要格式化輸出,但printf只有一個(gè),這該怎么辦? 我們解決方法是,修改fputc使得printf可以由3個(gè)串口分時(shí)復(fù)用,具體實(shí)現(xiàn)如下:

unsigned char us=0;

int fputc(int ch,FILE *f)
{
switch(us)
{
case 0:
while((USART1->SR&0X40)==0);
USART1->DR=(u8)ch; 
break;

case 1:
while((USART2->SR&0X40)==0);
USART2->DR=(u8)ch; 
break;

case 2:
while((USART3->SR&0X40)==0);
USART3->DR=(u8)ch; 
break;
}

return ch;
}
在調(diào)用的時(shí)候,根據(jù)需要將us賦以不同的值,printf就歸誰(shuí)所用了。
#define U_TO_DEBUG   us=0;
#define U_TO_ESP8266  us=1;
#define U_TO_SIM800   us=2;

U_TO_DEBUG
printf("hello world!");

U_TO_ESP8266
printf("AT
");


U_TO_SIM800
printf("AT
");

七、關(guān)于浮點(diǎn)數(shù)的傳輸

很多人不能很好的使用和處理浮點(diǎn),其主要根源在于對(duì)它的表達(dá)與存儲(chǔ)方式不是很理解。最典型的例子就是經(jīng)常有人問(wèn)我:“如何使用串口來(lái)發(fā)送一個(gè)浮點(diǎn)數(shù)?” 我們知道C語(yǔ)言中有很多數(shù)據(jù)類型,其中unsigned char、unsigned short、unsigned int、unsigned long我們稱其為整型,顧名思義它們可以表達(dá)整型數(shù)。而能夠表達(dá)的數(shù)值范圍與數(shù)據(jù)類型所占用的字節(jié)數(shù)有關(guān)。數(shù)值的表達(dá)方法比如簡(jiǎn)單,如下圖所示: ad61a4d2-1614-11ee-962d-dac502259ad0.jpg 一個(gè)字節(jié)可以表達(dá)0~255,兩個(gè)字節(jié)(unsigned short)自然就可以表達(dá)0~65535,依次類推。 當(dāng)需要把一個(gè)整型數(shù)值發(fā)送出去的時(shí)候,我們可以這樣作:

unsigned short a=0X1234;

UART_Send_Byte(((unsigned char *)&a)[0]);

UART_Send_Byte(((unsigned char *)&a)[1]);
也就是將構(gòu)成整型的若干字節(jié)順序發(fā)送即可。當(dāng)然,接收方一定要知道如何還原數(shù)據(jù),也就是說(shuō),它要知道自己接收到的若干字節(jié)拼在一起是什么類型,這是由具體通信協(xié)議來(lái)保障的。
unsigned char buf[2];
usnigned short a;

UART_Receive_Byte(buf+0);
UART_Receive_Byte(buf+1);

a=(*(usnigned short *)buf);
OK,關(guān)于整型比較容易理解。但換成float,很多人就有些迷糊了。因?yàn)閒loat的數(shù)值表達(dá)方式有些復(fù)雜。有些人使用下面的方法來(lái)進(jìn)行浮點(diǎn)的發(fā)送:
float a=3.14;

char str[10]={0};

ftoa(str,a); //**浮點(diǎn)轉(zhuǎn)為字符串* *即3.14**轉(zhuǎn)為"3.14"

UART_Send_Str(str); //**通過(guò)串口將字符串發(fā)出
很顯然,這種方法非常的“業(yè)余”。

還有人問(wèn)我:“浮點(diǎn)小數(shù)字前后的數(shù)字可以發(fā)送,但是小數(shù)點(diǎn)怎么發(fā)?”這赤裸裸的體現(xiàn)了他對(duì)浮點(diǎn)類型的誤解。

不要被float數(shù)值的表象迷惑,它實(shí)質(zhì)上只不過(guò)是4個(gè)字節(jié)而已,如下圖所示:

ad89b27e-1614-11ee-962d-dac502259ad0.jpg

所以,正確的發(fā)送浮點(diǎn)數(shù)的方法是這樣的:

float a=3.14;

UART_Send_Byte(((unsigned char *)&a)[0]);

UART_Send_Byte(((unsigned char *)&a)[1]);

UART_Send_Byte(((unsigned char *)&a)[2]);

UART_Send_Byte(((unsigned char *)&a)[3]);
接收者將數(shù)據(jù)還原為浮點(diǎn):
unsigned char buf[4];
float a;

UART_Receive_Byte(buf+0);

UART_Receive_Byte(buf+1);

UART_Receive_Byte(buf+2);

UART_Receive_Byte(buf+3);

a=*((float *)buf);

其實(shí)我們應(yīng)該發(fā)現(xiàn)數(shù)據(jù)類型的實(shí)質(zhì):不論是什么數(shù)據(jù)類型,它的基本組成無(wú)非就是內(nèi)存中存儲(chǔ)的若干個(gè)字節(jié)。只是我們?nèi)藶榈馁x予了這些字節(jié)特定的編碼方式或數(shù)值表達(dá)??创┝诉@些,我們就認(rèn)識(shí)到了數(shù)據(jù)的本質(zhì)了,我們甚至可以直接操作數(shù)據(jù)。

八、關(guān)于數(shù)據(jù)的直接操作

直接操作數(shù)據(jù)?我們來(lái)舉個(gè)例子:取一個(gè)整型數(shù)的相反數(shù)。一般的實(shí)現(xiàn)方法是這樣的:

int a=10;
int b=-a; //-1*a;
這樣的操作可能會(huì)涉及到一次乘法運(yùn)算,花費(fèi)更多的時(shí)間。當(dāng)我們了解了整型數(shù)的實(shí)質(zhì),就可以這樣來(lái)作:
int a=10;

int b=(~a)+1;
這也許還不足以說(shuō)明問(wèn)題,那我們?cè)賮?lái)看一個(gè)例子:取一個(gè)浮點(diǎn)數(shù)的相反數(shù)。似乎只能這樣來(lái)作:
float a=3.14;

float b=a*-1.0;
其實(shí),我們可以這樣來(lái)作:
float a=3.14;
float b;

((unsigned char *)&a)[3]^=0X80;
b=a;

沒(méi)錯(cuò),我們可以直接修改浮點(diǎn)在內(nèi)存中的高字節(jié)的符號(hào)位。這比乘以-1.0的方法要高效的多。

當(dāng)然,這些操作都需要你對(duì) C 語(yǔ)言中的指針有爐火純青的掌握。

九、浮點(diǎn)的四舍五入與比較

我們先說(shuō)第一個(gè)問(wèn)題:如何實(shí)現(xiàn)浮點(diǎn)的四舍五入?很多人遇到過(guò)這個(gè)問(wèn)題,其實(shí)很簡(jiǎn)單,只需要把浮點(diǎn)+0.5然后取整即可。 OK,第二個(gè)問(wèn)題:浮點(diǎn)的比較。這個(gè)問(wèn)題還有必要好好說(shuō)一下。 首先我們要知道,C語(yǔ)言中的判等,即==,是一中強(qiáng)匹配的行為。也就是,比較雙方必須每一個(gè)位都完全一樣,才認(rèn)定它們相等。這對(duì)于整型來(lái)說(shuō),是可以的。但是float類型則不適用,因?yàn)閮蓚€(gè)看似相等的浮點(diǎn)數(shù),其實(shí)它們的內(nèi)存表達(dá)不能保證每一個(gè)位都完全一樣。 這個(gè)時(shí)候,我們作一個(gè)約定:兩個(gè)浮點(diǎn)只要它們之差m足夠小,則認(rèn)為它們相等,m一般取10e-6。也就是說(shuō),只要兩個(gè)浮點(diǎn)小數(shù)點(diǎn)后6位相同,則認(rèn)為它們相等。也正是因?yàn)檫@個(gè)約定,很多C編譯器把float的精度設(shè)定為小數(shù)點(diǎn)后7位,比如ARMCC(MDK的編譯器)。

float a,b;

if(a==b)
... //**錯(cuò)誤

if(fabs(a-b) <= 0.000001)
...//**正確

十、出神入化的for循環(huán)

for循環(huán)我們?cè)偈煜げ贿^(guò)了,通常我們使用它都是中規(guī)中矩的,如下例:

int i;

for(i=0;i<100;i++)
{...}

但是,如果我們對(duì)for循環(huán)的本質(zhì)有更深刻的理解的話,就可以把它用得出神入化。

for后面的括號(hào)中的東西我稱之為“循環(huán)控制體”,分為三個(gè)部分,如下圖所示: ad9ba74a-1614-11ee-962d-dac502259ad0.jpg A、B、C三個(gè)部分,其實(shí)隨意性很大,可以是任意一個(gè)表達(dá)式。所以,我們可以這樣寫一個(gè)死循環(huán):

for(1;1;1) //1**本身就是一個(gè)表達(dá)式:常量表達(dá)式
{
...
}
當(dāng)然,我們經(jīng)常會(huì)把它簡(jiǎn)化成:
for(;;)
{
...
}
既然循環(huán)控制體中的A只是在循環(huán)開始前作一個(gè)初始化的操作,那我這樣寫應(yīng)該也沒(méi)毛?。?
int i=0;

for(printf("Number:
");i<10;i++)
{
printf(" %d
",i);
}
B是循環(huán)執(zhí)行的條件,而C是循環(huán)執(zhí)行后的操作,那我們就可以把一個(gè)標(biāo)準(zhǔn)的if語(yǔ)句寫成for的形式,而實(shí)現(xiàn)同樣的功能:
if(strstr("hello world!","abc"))
{
printf("Find Sub-string");
}
char *p;

for(p=strstr("hello world!","abc");p;p=NULL)
{
printf("Find Sub-string");
}

以上的例子可能有些雞肋,“一個(gè)if能搞定的事情,我為什么要用for?”,沒(méi)錯(cuò)。我們這里主要是為了解釋for循環(huán)的靈活用法。深入理解了它的本質(zhì),有助于我們?cè)趯?shí)際開發(fā)中讓工作事半功倍,以及看懂別人的代碼。

以下我再列舉幾個(gè)for循環(huán)靈活應(yīng)用的例子,供大家回味。 例1:

char *p;

for(p="abcdefghijklmnopqrstuvwxyz"; printf(p); p++)
printf("
");

提示:printf我們太熟悉了,但有幾個(gè)人知道printf是有返回值的?輸出應(yīng)該是怎樣的?

例2:

char *p;
unsigned char n;

for(p="ablmnl45ln",n=0;((*p=='l')?(n++):0),*p;p++);
提示:還記得C語(yǔ)言中的三目運(yùn)算和逗號(hào)表達(dá)式嗎?n應(yīng)該等于幾?

例3:

unsigned char *index="C[XMZA[C[NK[RDEX@";

char *alphabet="EHUIRZWXABYPOMQCTGSJDFKLNV ";

int i=0;

for(;(('@'!=index[i])?1:(printf("!!Onz
"),0));i++)
{
printf("%c",alphabet[index[i]-'A']);
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19104

    瀏覽量

    304797
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7604

    瀏覽量

    136684
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3614

    瀏覽量

    93686

原文標(biāo)題:C語(yǔ)言的一些“騷操作”及其深層理解

文章出處:【微信號(hào):玩點(diǎn)嵌入式,微信公眾號(hào):玩點(diǎn)嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    怎么才能做好嵌入式開發(fā)?學(xué)好C語(yǔ)言吧!今天就來(lái)推薦篇大佬寫的嵌入式C
    發(fā)表于 09-27 09:53 ?1172次閱讀

    如何成為嵌入式C語(yǔ)言高手?

    如何成為嵌入式C語(yǔ)言高手? 嵌入式系統(tǒng)是當(dāng)今科技領(lǐng)域的核心,而C
    發(fā)表于 03-25 14:12

    如何成為嵌入式C語(yǔ)言高手?

    如何成為嵌入式C語(yǔ)言高手? 嵌入式系統(tǒng)是當(dāng)今科技領(lǐng)域的核心,而C
    發(fā)表于 04-07 16:03

    學(xué)嵌入式軟件開發(fā)需要什么知識(shí)??

    C語(yǔ)言,匯編,數(shù)據(jù)結(jié)構(gòu),linux高級(jí)編程,ARM系統(tǒng),嵌入式內(nèi)核,嵌入式驅(qū)動(dòng)。嵌入式需要學(xué)習(xí)的知識(shí)
    發(fā)表于 09-30 09:32

    學(xué)嵌入式軟件開發(fā)需要什么知識(shí)?

    知識(shí)點(diǎn)就這些。,要求精通C語(yǔ)言編程,最好有些匯編知識(shí). 二,要求英語(yǔ)功底要好,因?yàn)?b class='flag-5'>一些芯片手
    發(fā)表于 10-14 09:19

    梳理嵌入式Linux的一些知識(shí)

    前言這篇文章簡(jiǎn)單我們來(lái)起梳理嵌入式Linux的一些知識(shí),方便于一些想跟我樣想要由單片機(jī)進(jìn)階到
    發(fā)表于 11-04 07:33

    分享一些嵌入式方面的基礎(chǔ)知識(shí)

    同時(shí)更關(guān)鍵的是為了補(bǔ)齊一些嵌入式方面的基礎(chǔ)知識(shí),做如下筆記,持續(xù)記錄:1.嵌入式系統(tǒng)基礎(chǔ)知識(shí)(1) 嵌入
    發(fā)表于 11-08 07:41

    介紹嵌入式系統(tǒng)的一些基礎(chǔ)知識(shí)

    本文主要介紹嵌入式系統(tǒng)的一些基礎(chǔ)知識(shí),希望對(duì)各位有幫助。嵌入式系統(tǒng)基礎(chǔ)1、嵌入式系統(tǒng)的定義(1)定義:以應(yīng)用為中心,以計(jì)算機(jī)技術(shù)為基礎(chǔ),軟硬
    發(fā)表于 12-21 07:32

    嵌入式C語(yǔ)言知識(shí)點(diǎn)匯總,絕對(duì)實(shí)用

    一些這方面的經(jīng)驗(yàn)和思考,就希望總結(jié)下來(lái),系統(tǒng)的闡述嵌入式C語(yǔ)言的重要知識(shí)點(diǎn),就是這篇文章的由來(lái)。本文以自己在
    發(fā)表于 02-17 06:10

    嵌入式C語(yǔ)言進(jìn)階之道

    的總結(jié)。本文涉及的 知識(shí)點(diǎn)多數(shù)來(lái)自于網(wǎng)絡(luò),其中加入我個(gè)人理解以及自己平時(shí)遇到的注意點(diǎn)。 本文從編程風(fēng)格談起,講述了模塊化的編程方法,對(duì)一些大型項(xiàng)目中常用重點(diǎn)關(guān)鍵字做 了講解,參照 MISRA C 2004 規(guī)范 ,對(duì)
    發(fā)表于 04-19 10:15

    嵌入式c語(yǔ)言編程(由淺入深)

    本內(nèi)容詳細(xì)介紹了嵌入式c語(yǔ)言編程的各項(xiàng)知識(shí),包括嵌入式c語(yǔ)言
    發(fā)表于 11-02 14:37 ?0次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>c</b><b class='flag-5'>語(yǔ)言</b>編程(由淺入深)

    嵌入式系統(tǒng)的一些基礎(chǔ)知識(shí)

    本文主要介紹嵌入式系統(tǒng)的一些基礎(chǔ)知識(shí),希望對(duì)各位有幫助。
    的頭像 發(fā)表于 02-18 10:44 ?2386次閱讀

    C語(yǔ)言嵌入式培訓(xùn) 嵌入式C語(yǔ)言程序設(shè)計(jì)基礎(chǔ)

      學(xué)習(xí)嵌入式的基礎(chǔ)語(yǔ)言C語(yǔ)言,因此先掌握C語(yǔ)言對(duì)于后續(xù)
    發(fā)表于 11-03 21:06 ?32次下載
    <b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>嵌入式</b>培訓(xùn)  <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>程序設(shè)計(jì)基礎(chǔ)

    嵌入式C語(yǔ)言知識(shí)總結(jié)

    一些這方面的經(jīng)驗(yàn)和思考,就希望總結(jié)下來(lái),系統(tǒng)的闡述嵌入式C語(yǔ)言的重要知識(shí)點(diǎn),就是這篇文章的由來(lái)。本文以自己在
    發(fā)表于 12-20 19:44 ?12次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>知識(shí)</b>總結(jié)

    嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    導(dǎo)讀:怎么做好嵌入式?相信這個(gè)問(wèn)題無(wú)論問(wèn)誰(shuí)你都會(huì)得到句學(xué)好C語(yǔ)言!今天推薦篇大佬寫的嵌入式
    的頭像 發(fā)表于 04-13 11:12 ?2702次閱讀
    RM新时代网站-首页