1.php有zend引擎去編譯php,那c呢?是作業系統在編譯他嗎?
2.很多年以前就知道電腦只認識01代碼,但今天腦袋瓜就想,電腦的那一部分只認識01,我理解的是cpu只認識01對嗎?
3.c和作業系統的關係是什嗎?比如我在windows下用c編譯的東西能在linux下用嗎,我感覺是不行的,那是不是我同樣的代碼,要想在linux用的話,那就必須copy一份到linux下在編譯。
4,我發現曾經用過很多東西,感覺真的是在用人家的東西,不管學js也好php也好,html,人家到底底層咋實層的,他和電腦整個的更深一層是怎麼互動的,完全不知道啊。學起c來感覺自己更像一個菜鳥。
真是個菜鳥,問了很多小白的問題,但我真的是不知道。先謝謝segmentfault的朋友了。
回複內容:
1.php有zend引擎去編譯php,那c呢?是作業系統在編譯他嗎?
2.很多年以前就知道電腦只認識01代碼,但今天腦袋瓜就想,電腦的那一部分只認識01,我理解的是cpu只認識01對嗎?
3.c和作業系統的關係是什嗎?比如我在windows下用c編譯的東西能在linux下用嗎,我感覺是不行的,那是不是我同樣的代碼,要想在linux用的話,那就必須copy一份到linux下在編譯。
4,我發現曾經用過很多東西,感覺真的是在用人家的東西,不管學js也好php也好,html,人家到底底層咋實層的,他和電腦整個的更深一層是怎麼互動的,完全不知道啊。學起c來感覺自己更像一個菜鳥。
真是個菜鳥,問了很多小白的問題,但我真的是不知道。先謝謝segmentfault的朋友了。
你問了很多電腦體繫結構的事情,其實學習c語言也不需要知道這麼多,但是你是一個有好奇心的人,且邏輯思維也算清楚。
01這東西不是軟體關心的,是硬體關心,在數字邏輯中,我們稱其為高低電平,電流經過一個元器件,如果電壓為高電壓記為0,低電壓記為1。將一個邏輯經過運算之後,結合元器件的特性,我們就可以通過元器件的組合來將這個邏輯運算表達出來。剛開始肯定是簡單的二極體之類的,發展到現在就是你看到的cpu了,裡面的晶體管小到可以用納米計算。電腦中的計算任務最終交給cpu,當然上層作業系統上的一個隨隨便便的命令,cpu是不認識的,你在作業系統中的一個命令要被拆分成若干指令,而每個指令去實現的時候又被分配到不同的電路單元中進行處理。這些指令的處理過程在電路中其實是一連串的01運算。這些指令(全部由二進位程式碼群組成)就是傳說中的機器碼,由於機器碼對於人來說閱讀太困難,所以前輩們將其轉成了組合語言,組合語言的開發速度和學習成本還是不理想,所以才有了進階語言的誕生。
c語言其實最終還是要轉化成機器碼。比如說int a = 1;
在編譯是,要被先翻譯成好幾句彙編,然後這些彙編再轉成機器碼。所以,說白了編譯就是將c變成彙編再變成機器碼的過程,編譯之後產生的可執行程式又可以愉快的向cpu髮指令了。
跟c語言不通,php是解析型語言,他不需要直接編譯成可執行程式,他的代碼使用zend引擎來做解析。zend引擎可以理解為一個可執行程式,當他通過詞法、文法解析知道你要幹什麼後,就直接調用程式內建的一個函數交給你一個處理結果。
至於你說的linux程式和windows程式不相容的問題,是因為這作業系統產生可執行程式的二進位格式不一樣,作業系統根本就彼此不識別。
c語言的學習關鍵是理解文法,先學會使用,推薦看《c專家編程》、《c和指標》
gcc vc clang icc 都是c語言的編譯器。
是的。cpu只認機器碼,助記符是人類為了便於寫彙編發明的抽象。
作業系統大部分是拿c寫的。windows和linux雖然都跑x86的程式,但是由於可執行檔格式不同,不能直接相容。現在好像有應用級虛擬機器能實現這一點。
js、php、py等指令碼語言的解譯器是用c實現的,c語言負責和系統打交道,指令碼語言的庫中有一部分調用系統api來和系統打交道。學c的時候再關心底層互動,學其他進階語言的時候主要應該關心商務邏輯。
哥們應該不是科班出身吧,你這些疑問其實看看電腦原理一類的書,很快就會明白的。
這裡寫一些簡陋的介紹,電腦系統本身是個層層抽象的過程。
最底層當然是晶體管電路,通過電路抽象成各種數字邏輯,我們可以實現算術運算(比如加減),邏輯運算(轉移複製)之類的操作。
然後是指令系統,指機器指令的集合(上一條對電路的抽象稱為“微指令”),又是抽象,把邏輯電路的準系統封裝成加減乘除、浮點運算、字串處理等等。所謂“機器語言”就是一串指令代碼。
再然後組合語言,因為 0101 對人實在沒意義,於是起了個代號,就是組合語言,比如用ADD
(加)代表001
,這樣小小的抽象就有語義了。而運行組合語言寫出來的程式,就是再翻譯成原來的位元機器語言。
最後就是進階語言,比如C,因為組合語言的抽象程度太低,還是很麻煩,才出現進階語言。C語言更接近自然語言了。而 C 需要編譯(這就是編譯器的作用),在沒有 OS(作業系統)時,同樣也只是翻譯成機器語言,而在有作業系統時,因為需要 OS 確定怎麼使用這個程式,編譯出的可執行檔就不光是機器指令了,還得有一定格式,加個檔案頭之類的,不同 OS 要求的格式不一樣。
這裡就可以回答LZ一個問題,編譯出來的可執行檔為什麼不能跨平台(扯了半天才回答一個問題)
第一 程式面向的硬體如cpu可能不一樣,硬體不同當然指令就不同了,所需要的機器語言當然也不同 第二 不同 OS 編譯的可執行檔程式格式不一樣,其他 OS 識別不了 第二 不同 OS 的程式中往往會叫用作業系統的api(形介面api),api都不一樣當然不能跨平台
寫著寫著都不想寫了,非常簡陋,很多重要的地方都略過去,大概看看吧,也算是自己對以前知識的一個回顧
php程式員這個得定義好.
程式員: 電腦基礎良好,對編譯原理有瞭解,知道一門語言是如何編譯成目標代碼的.圖形學,大致知道矩陣變化,向量,歐拉角,四元數的基礎知識.
php:你在程式員的基礎之上對PHP這門語言比較感興趣,能通過編譯原理的基礎瞭解這門語言的編譯方式.知道 PHP為什麼以fastcgi的方式運行能將你編寫代碼的生命週期縮短,讓編程的商務邏輯降到最小.
你覺得你是PHP程式員嗎?
1、gcc編譯器
2、是,以前是用電子管,發展到現在的晶體管,超大規模電路整合,現在已經不止是數以千萬計的了。
3、是不行的,linux和windows核心是完全不同的,可以通過其它辦法實現linux下運行。
4、學習本來就是如此,你越追究越底層,就像你學其它比較進階的程式設計語言時,你會發現C更底層了,你發現能對指標操作,你學了C你會發現彙編更底層了,你會發現在死繞彎子,他更難用了。當然還有更底層的,我聽我老師說他老師,學的是彙編,用的是打孔技術,我也沒接觸過,不過我知道是把組譯工具原始碼寫在專用的紙袋上,也沒有調試這種說法,只有靠自己,可以用貼紙物品貼掉孔,但是這基本用於誤打或者打錯,程式錯了基本上很難糾正,然後按照代碼的每一行對應的機械碼,好像是無孔為0,無孔為1。
你想學到底層,那麼你首先要站的是程式員的位置,從程式員的角度上學下去,你會發現你又接觸了另一門學科。如果是想簡單的去瞭解和涉及底層,玩玩嵌入式也是可以的。嵌入式也是現在流行的,智能家居正是產物。
1.gcc,clang等編譯器
2.電腦任何硬體部分都只懂1和0
3.c是一種程式設計語言,作業系統是用一種程式設計語言寫出來的一組程式。包括不限於記憶體管理,任務調度,磁碟管理,系統調用等等。把硬體進行有效管理並抽象成一套統一的API供應用程式調用。各個系統之間的程式不通用,因為他們所應用的系統調用是不一樣的。一個printf函數在不同平台的C庫中實現肯定是不一樣的。
C庫也打包隱藏了很多底層細節,編譯器也協助我們做了很多。比如main函數預設會與一些程式運行相關的函數,應用程式的ELF/PE格式封裝等等。學了x86彙編表示其實底層下面還有更低層 XD
看《深入理解電腦系統》
建議題主在網上下一本《C Primer Plus》,只看第一章概覽就可以解答你現在大部分問題。
不同作業系統的二進位可執行檔的格式是不一樣的,比如Linux上是ELF,Windows上是PE。比如Linux上可以用readelf -a /bin/cat
查看程式cat的ELF資訊,比如可以看到該程式的進入點地址0x402602,以及程式依賴的共用庫等資訊。
Linux執行程式,就是根據二進位可執行檔的ELF資訊建立記憶體布局,比如 cat /proc/self/maps
查看cat載入表(記憶體布局):
00400000-0040b000 r-xp 00000000 08:06 4198651 /bin/cat (text段)0060a000-0060b000 r--p 0000a000 08:06 4198651 /bin/cat (data段)0060b000-0060c000 rw-p 0000b000 08:06 4198651 /bin/cat (bss段)016be000-016df000 rw-p 00000000 00:00 0 [heap] (下面省略程式依賴的各個共用庫地址)7fff31d00000-7fff31d21000 rw-p 00000000 00:00 0 [stack] (下面省略vdso和vsyscall)
其中的text段(程式碼片段)存放的就是ELF檔案包含的程式執行代碼,即CPU的機器指令。
記憶體布局建立完成後,跳到程式的第一條機器指令,開始執行。
同一段C代碼,在同一個機器、同一個作業系統上使用不同的編譯器(如GCC、Clang/LLVM)產生的二進位檔案包含的機器指令,不一定完全相同,因為不同編譯器可能有自己不同的最佳化實現,比如Intel的編譯器ICC編譯的程式對同為x86架構的AMD處理器支援就不好,應該是Intel使用了自己CPU專屬的特性。
在同一個機器,不同作業系統編譯產生的二進位檔案包含的機器指令,區別可能就更大了,雖然這些機器指令都能被當前機器(CPU)識別和執行。
不同的CPU架構有不同的指令集,能識別的機器指令自然也是不同的,所以x86上的二進位程式,不能直接運行於ARM上,不過可以使用交叉編譯器比如arm-none-linux-gnueabi或者Android NDK,在Linux x86上產生ARM的二進位檔案(機器碼)。
拿PHP來說,我們編寫的代碼是交給Zend Engine來啟動並執行,而不是直接交給CPU運行,所以只要保證Zend Engine跨平台,我們的PHP代碼就能跨平台。PHP的opcode之於Zend Engine,類似於機器碼之於CPU,我們可以使用PECL擴充vld查看PHP程式的作業碼opcode。
我不是科班的,但我有我的理解
比如要建一個房子,我們用磚頭,水泥,鋼筋等,不同的房子用不同的材料,比如用木頭也能蓋一個房子。這就好比用進階語言寫一個程式。可以用不同的語言來實現。但是磚頭,水泥,鋼筋等材料是別人造好的,如果所有都要我們自己造,那幾乎不可能,底層就是如何製造這些基礎的材料,對於建築工人我們需要瞭解這些材料的特性,這樣我們才能有機組合建造最理想的大樓,我們需要關注我們建造工藝本身,至於材料可以交給專門造這些的人去研究,這樣大家才能各自發揮自己的力量,程式員也一樣。