日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言 字符相加_C语言中自加自减的编译原理

發(fā)布時(shí)間:2024/9/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言 字符相加_C语言中自加自减的编译原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

自增自減規(guī)則

i++ 與 ++i 的主要區(qū)別有兩個(gè):

1、 i++ 返回原來的值,++i 返回加1后的值。 2、 i++ 不能作為左值,而++i 可以。

毫無疑問大家都知道第一點(diǎn)(不清楚的看下下面的實(shí)現(xiàn)代碼就了然了),我們重點(diǎn)說下第二點(diǎn)。 首先解釋下什么是左值(以下兩段引用自中文維基百科『右值引用』詞條)。

左值是對應(yīng)內(nèi)存中有確定存儲(chǔ)地址的對象的表達(dá)式的值,而右值是所有不是左值的表達(dá)式的值。

一般來說,左值是可以放到賦值符號(hào)左邊的變量。

但能否被賦值不是區(qū)分左值與右值的依據(jù)。比如,C++的const左值是不可賦值的;而作為臨時(shí)對象的右值可能允許被賦值。左值與右值的根本區(qū)別在于是否允許取地址&運(yùn)算符獲得對應(yīng)的內(nèi)存地址。

比如,

int i = 0; int *p1 = &(++i); //正確 int *p2 = &(i++); //錯(cuò)誤 ++i = 1; //正確 i++ = 5; //錯(cuò)誤

那么為什么『i++ 不能作為左值,而++i 可以』? 看它們各自的實(shí)現(xiàn)就一目了然了:

// 前綴形式: int& int::operator++() //這里返回的是一個(gè)引用形式,就是說函數(shù)返回值也可以作為一個(gè)左值使用 {//函數(shù)本身無參,意味著是在自身空間內(nèi)增加1的 *this += 1; // 增加 return *this; // 取回值 } //后綴形式: const int int::operator++(int) //函數(shù)返回值是一個(gè)非左值型的,與前綴形式的差別所在。 {//函數(shù)帶參,說明有另外的空間開辟 int oldValue = *this; // 取回值 ++(*this); // 增加 return oldValue; // 返回被取回的值}

如上所示,i++ 最后返回的是一個(gè)臨時(shí)變量,而臨時(shí)變量是右值。

運(yùn)算符讀取規(guī)則

C語言對于解決這個(gè)問題的解決方案可以歸納為一個(gè)很簡單的規(guī)則:每一個(gè)符號(hào)應(yīng)該包含盡可能多的字符。也就是說,編譯器將程序分解成符號(hào)的方法是:從左到右一個(gè)一個(gè)字符的讀入,字符一個(gè)字符地讀入,如果該字符可能組成一個(gè)符號(hào),那么再讀入下一個(gè)字符,判斷已經(jīng)讀入的兩個(gè)字符組成的字符串是否可能是一個(gè)符號(hào)的組成部分;如果可能,繼續(xù)讀入下一個(gè)字符,重復(fù)上述判斷,直到讀入的字符組成的字符串已不再可能組成一個(gè)有意義的符號(hào)。這個(gè)處理策略有時(shí)被稱為“貪心法”,或者,更口語化一點(diǎn),稱為“大嘴法”,Kernighan與Ritchie對這個(gè)方法的表述如下,“如果(編譯器的)輸入流截止至某個(gè)字符之前都已經(jīng)被分解為一個(gè)個(gè)符號(hào),那么下一個(gè)號(hào)將包括從該字符之后可能組成一個(gè)符號(hào)的最長字符串?!?/p>

? ---《C陷阱和缺陷》 第八頁

編譯器編譯情況

自增(后綴):

Turbo C中,先統(tǒng)一取值后依次自增;

VS中,從左向右依次取值自增;

int a,i=5; a=i+++i+++i++; //按照貪心算法,結(jié)果為(i++)+(i++)+(i++) //Turbo C中:a=5+5+5=15,i=8 //VS中:a=5+6+7=18,i=8

以下編譯出錯(cuò)

int a,i=5; a=++i+++i+++i; //編譯錯(cuò)誤 //編譯器編譯后,((++i)++)+(i++)+i

++i返回的是一個(gè)引用形式,無法在對(++i)在進(jìn)行自增。

匯編代碼

gcc編譯(++i)+(++i)+(++i)特別奇怪。。。

#include <stdio.h>int main() {int i=3;printf("%d",(++i)+(++i)+(++i));return 0; }

匯編代碼(主要看main函數(shù))

000000000000064a <main>:64a: 55 push %rbp /賦值?/64b: 48 89 e5 mov %rsp,%rbp /rsp,rbp為堆棧地址?/64e: 48 83 ec 10 sub $0x10,%rsp /值為16/652: c7 45 fc 03 00 00 00 movl $0x3,-0x4(%rbp) /把i=3長字節(jié)放在rbp堆棧/659: 83 45 fc 01 addl $0x1,-0x4(%rbp) /i=i+1放入rbp堆棧/65d: 83 45 fc 01 addl $0x1,-0x4(%rbp) /i=i+1放入rbp堆棧,此時(shí)i=5/661: 8b 45 fc mov -0x4(%rbp),%eax /把rbp短字節(jié)(i=5)堆棧值,移動(dòng)到寄存器ax/64a: 55 push %rbp /賦值?/64b: 48 89 e5 mov %rsp,%rbp /rsp,rbp為堆棧地址?/64e: 48 83 ec 10 sub $0x10,%rsp /值為16/652: c7 45 fc 03 00 00 00 movl $0x3,-0x4(%rbp) /把i=3長字節(jié)放在rbp堆棧/659: 83 45 fc 01 addl $0x1,-0x4(%rbp) /i=i+1放入rbp堆棧/65d: 83 45 fc 01 addl $0x1,-0x4(%rbp) /i=i+1放入rbp堆棧,此時(shí)i=5/661: 8b 45 fc mov -0x4(%rbp),%eax /把rbp短字節(jié)(i=5)堆棧值,移動(dòng)到寄存器ax/664: 8d 14 00 lea (%rax,%rax,1),%edx /寄存器ax與寄存器ax相加放到寄存器dx/ /dx=10/667: 83 45 fc 01 addl $0x1,-0x4(%rbp) /i=i+1=6放入rbp堆棧/66b: 8b 45 fc mov -0x4(%rbp),%eax /把結(jié)果i=6移動(dòng)到寄存器ax/66e: 01 d0 add %edx,%eax /把寄存器dx與寄存器ax相加,也就是10+6/670: 89 c6 mov %eax,%esi /把16移動(dòng)到寄存器si/672: 48 8d 3d 9b 00 00 00 lea 0x9b(%rip),%rdi # 714 <_IO_stdin_used+0x4> /我也沒看懂/ 679: b8 00 00 00 00 mov $0x0,%eax /寄存器ax賦值/67e: e8 9d fe ff ff callq 520 <printf@plt> /調(diào)用fun函數(shù)printf/683: b8 00 00 00 00 mov $0x0,%eax /寄存器ax賦值/688: c9 leaveq 689: c3 retq 68a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) //

可以看出,先自增兩次,相加,再自增,再相加,后賦值。 gcc是不是不符合規(guī)范?他并不像書上說的,自增比加號(hào)的優(yōu)先級(jí)高。

總結(jié)

以上是生活随笔為你收集整理的c语言 字符相加_C语言中自加自减的编译原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。