国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C語言】程序環(huán)境和預(yù)處理

這篇具有很好參考價值的文章主要介紹了【C語言】程序環(huán)境和預(yù)處理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

程序環(huán)境和預(yù)處理

本章重點

  • 程序的編譯環(huán)境
  • 程序的執(zhí)行環(huán)境
  • 詳解:C語言程序的編譯加鏈接
  • 預(yù)定義符號介紹
  • 預(yù)處理指令#define
  • 宏和函數(shù)的對比
  • 預(yù)處理操作符#和##的介紹
  • 命令定義
  • 預(yù)處理指令#include
  • 預(yù)處理指令#undef
  • 條件編譯

程序的編譯環(huán)境和執(zhí)行環(huán)境

在ANSIC的任何一種實現(xiàn)中,存在兩種不同的環(huán)境:

第一種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令

第二種是執(zhí)行環(huán)境,它用于實際執(zhí)行代碼

詳解編譯+鏈接

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

  • 組成一個程序的每個源文件通過編譯過程分別轉(zhuǎn)換成目標(biāo)代碼(object code
  • 每個目標(biāo)文件由鏈接器捆綁在一起,形成一個單一而完整的可執(zhí)行程序
  • 鏈接器同時也會引入標(biāo)準(zhǔn)C函數(shù)庫中任何被該程序所用到的函數(shù),而且他可以搜索程序猿個人的程序庫,將其需要的函數(shù)也鏈接到程序中
編譯本身也分為幾個階段

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

如何查看編譯期間每一步都發(fā)生了什么呢?

  1. 預(yù)處理選項gcc -E test.c -o test.i預(yù)處理完成后停下來,預(yù)處理之后產(chǎn)生的結(jié)果都放在test.i文件中
  2. 編譯選項gcc -s test.c,編譯完成之后就停下來,結(jié)果保存在test.s
  3. 匯編gcc -c test.c,匯編完成之后就停下來,結(jié)果保存在test.o
運行環(huán)境

程序執(zhí)行過程:

  1. 程序必須載入內(nèi)存中。在有操作系統(tǒng)的環(huán)境中:一般這個由操作系統(tǒng)完成。在獨立的環(huán)境中,程序的載入必須由手工安排,也可能是通過可執(zhí)行代碼置入只讀內(nèi)存來完成。
  2. 程序的執(zhí)行便開始。接著調(diào)用main函數(shù)。
  3. 開始執(zhí)行程序代碼。這個時候的程序?qū)⑹褂靡粋€運行時堆棧,存儲函數(shù)的局部變量和返回地址。程序同時也是用靜態(tài)內(nèi)存(static),存儲靜態(tài)內(nèi)存中的變量在程序的整個執(zhí)行過程中一直保留他們的值
  4. 終止程序。正常終止main函數(shù);也有可能是意外終止

預(yù)處理詳解

預(yù)定義符號
#include <stdio.h>

int main() {
	printf("%s\n", __FILE__);// 進行編譯的源文件
	printf("%d\n", __LINE__);// 文件當(dāng)前的行號
	printf("%s\n", __DATE__);// 文件被編譯的日期
	printf("%s\n", __TIME__);// 文件被編譯的時間
	printf("%s\n", __STDC__);// 如果編譯器遵循ANSIC,其值為1, 否則未定義
}
#define
#define定義標(biāo)識符
#define MAX 1000
#define reg register //為 register這個關(guān)鍵字,創(chuàng)建一個簡短的名字
#define do_forever for(;;) //用更形象的符號來替換一種實現(xiàn)
#define CASE break;case //在寫case語句的時候自動把 break寫上。
// 如果定義的 stuff過長,可以分成幾行寫,除了最后一行外,每行的后面都加一個反斜杠(續(xù)行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
							date:%s\ttime:%s\n" ,\
							__FILE__,__LINE__ , \
								__DATE__,__TIME__ )

define定義的時候,要不要在最后加上;?

不要加,這樣會導(dǎo)致語法錯誤

#define定義宏

#define 機制包括了一個規(guī)定,允許把參數(shù)替換到文本當(dāng)中,這種實現(xiàn)稱為宏或定義宏

下面是宏的申明方式:

#define name(parament-list) stuff

? 其中parament-list是一個由逗號隔開的符號表,它們可能出現(xiàn)在stuff當(dāng)中

注意

參數(shù)列表的左括號必須與name緊鄰。

如果兩者之間有任何的空白存在,參數(shù)列表就會被解釋為stuff的一部分。

如:

#define SQUARE(X) X * X

這個宏接收一個參數(shù)X.如果在上述聲明之后,你把

SQARE(5);

置于程序中,預(yù)處理就會用下面這個表達式替換上面的表達式:

5 * 5;

警告

這個宏存在一個問題:觀察下面的代碼:

int a = 5;
printf("%d ", SQARE(a + 1));

突然看到,我們可能會覺得這個程序打印36,事實上打印的卻是11,這是為什么?

替換時,參數(shù)X被替換成了a+1,所以這條語句實際上變成了:

printf("%d\n", a + 1 * a + 1);

這樣就可以清晰地看到了,由替換產(chǎn)生地表達式并沒有按照預(yù)想的次序進行求值。在宏定義地時候加上兩個括號,這個問題就輕松地解決了:

#define SQUARE(X) (X) * (X);

這樣預(yù)處理之后就產(chǎn)生了預(yù)期地效果:

printf("%d\n", (a + 1) * (a + 1));

提示

所以用于數(shù)值表達式進行求值的宏定義都應(yīng)該用這種方式加上括號,避免在使用宏時由于參數(shù)中的操作符或鄰近操作符之間不可預(yù)料的相互作用。

#define替換規(guī)則

在程序中擴展#define定義符號和宏時,需要涉及幾個步驟:

  1. 在調(diào)用宏的時候,首先對參數(shù)進行檢查,看看是否包含任何由#define定義的符號。如果是,它們首先被替換。
  2. 替換文本隨后被插入到程序中原來文本的位置。對于宏,參數(shù)名被他們的值所替換。
  3. 最后,再次對結(jié)果進行掃描,看看是否包含由#define定義的符號。如果是,就重復(fù)上述過程。

注意

  1. 宏參數(shù)和#define定義中可以出現(xiàn)其他#define定義的符號。但是對于宏,不能出現(xiàn)遞歸。
  2. 當(dāng)預(yù)處理器搜索#define定義的符號的時候,字符串常量的內(nèi)容并不被搜索。
#和##

如何把參數(shù)插入到字符串中?

首先我們看看這個代碼:

char* p = "hello ""bit\n";
printf("hello "" bit\n");
printf("%S", p);

這里的輸出是:

hello bit?

我們發(fā)現(xiàn)字符串是有自動連接功能的。

  1. 那我們是不是可以寫出這樣的代碼?
#define PRINT(FORMAT, VALUE)
	printf("the value is "FORMAT"\n", VALUE);
PRINT("%d", 10);

這里只有當(dāng)字符串作為宏參數(shù)的時候才可以把字符串放在字符創(chuàng)當(dāng)中。

  1. 另一個技巧就是:

使用#,把一個宏參數(shù)變成對應(yīng)的字符串。

比如:

int i = 10;
#define PRINT(FORMAT, VALUE);
	printf("the value of "#VALUE" is "FORMAT"\n", VALUE);
PRINT("%d", i + 3);

最終的結(jié)果應(yīng)該是:

the value of i + 3 is 13

##的作用

##可以把位于它兩邊的符號合成一個符號。它允許宏定義從分離的文本片段創(chuàng)建標(biāo)識符

#define ADD_TO_SUM(name, value);
	sum##num += value;
...
ADD_TO_SUM(5,10);//作用是給sum5增加到10

注:這樣的連接必須產(chǎn)生一個合法的標(biāo)識符。否則其結(jié)果就是未定義的。

帶副作用的宏參數(shù)

當(dāng)宏參數(shù)在宏的定義中出現(xiàn)超過一次的時候,如果參數(shù)帶有副作用,那么你在使用這個宏的時候就可能出現(xiàn)危險,導(dǎo)致不可預(yù)測的結(jié)果。副作用就是表達式求值的時候出現(xiàn)的永久性的效果

例如:

x+1;//不帶副作用
x++;//帶有副作用

樣例:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b));

int main() {
	int x = 5;
	int y = 8;
	int z = MAX(x++, y++);
	printf("x = %d, y = %d, z = %d\n", x, y, z);//輸出結(jié)果是什么?
	return 0;
}

在這里我們得知道預(yù)處理器處理之后的結(jié)果是什么:

z = ( (x++) > (y++) ? (x++) : (y++));

所以輸出的結(jié)果是:

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

宏和函數(shù)的對比

宏通常被應(yīng)用于執(zhí)行簡單的計算。

比如在兩個數(shù)中找出較大的一個,為什么不用函數(shù)來實現(xiàn)那?

原因有二:

  1. 用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實際執(zhí)行這個小型計算工作所需的時間更多。所以宏比函數(shù)在程序的規(guī)模和速度方面更勝一籌
  2. 更為重要的是函數(shù)的參數(shù)必須聲明為特定的類型。所以函數(shù)只能在類型合適的表達式上使用。反之這個宏可以適用于整形、長整型、浮點型等可以用于來比較的類型宏與類型無關(guān)的

宏的缺點

  1. 每次使用宏的時候,一份宏定義地代碼將插入到程序中。除非宏比較短,否則可能大幅度增加程序的長度。
  2. 宏時沒法調(diào)試的
  3. 宏由于類型無關(guān),也不夠嚴(yán)謹(jǐn)。
  4. 宏可能帶來運算符優(yōu)先級的問題,導(dǎo)致程序容易出錯。

宏有時候可以做到函數(shù)做不到的事情。比如:宏的參數(shù)可以出現(xiàn)類型,但是函數(shù)做不到。

#include <stdio.h>
#include <stdlib.h>

#define MALLOC(num, type) (type*)malloc(num*sizeof(type)) 

int main() {
	int* p = MALLOC(10, int);
	return 0;
}

宏和函數(shù)的一個對比

屬性 #define定義宏 函數(shù)
代碼長度 每次使用的時候,代碼都會被插入到程序中。除了非常小的宏之外,程序的長度會大幅度增長 函數(shù)只出現(xiàn)于一個地方;每次使用這個函數(shù)時,都調(diào)用那個地方的同一份代碼
執(zhí)行速度 更快 存在函數(shù)的調(diào)用和返回的額外開銷,所以相對慢一些
操作符優(yōu)先級 宏參數(shù)的求值是在所有周圍表達式的上下文環(huán)境里,除非加上括號,否則鄰近操作符的優(yōu)先級可能會產(chǎn)生不可預(yù)料的后果,所以建議宏在書寫的時候多加一些括號 函數(shù)的參數(shù)只在調(diào)用的時候求值一次,它的結(jié)果值傳遞給函數(shù)。表達式的求值更容易預(yù)測
帶有副作用的參數(shù) 參數(shù)可以被替換到宏體的多個位置,所以帶有副作用的參數(shù)求值可能會產(chǎn)生不可預(yù)料的結(jié)果 函數(shù)參數(shù)只在傳參的時候求值一次,結(jié)果更容易控制。
參數(shù)類型 宏的參數(shù)與類型無關(guān),只要對參數(shù)的操作是合法的,它就可以適用于任何參數(shù)類型 函數(shù)的參數(shù)是與類型有關(guān)的,如果參數(shù)類型不同,就需要不同的函數(shù),即使它們執(zhí)行的任務(wù)是相同的
調(diào)試 宏是不方便調(diào)試的 函數(shù)是可以逐語句調(diào)試的
遞歸 宏是不能遞歸的 函數(shù)是可以遞歸的
命名約定

一般來講函數(shù)的宏的使用語法很相似。所以語言本身沒法幫我們區(qū)分二者。那我們平時的一個習(xí)慣是:

把宏名全部大寫

函數(shù)名不要全部大寫

#undef

這條指令用于移除一個宏定義。

命令行定義

許多C編譯器提供了一種能力,允許在命令行中定義符號。用于啟動編譯過程。例如:當(dāng)我們根據(jù)同一個源文件要編譯出一個程序的不同的版本的時候,這個特性有點用處。(假設(shè)某個程序中聲明了一個某個長度的數(shù)組,如果機器內(nèi)存有限,我們需要一個很小的數(shù)組,但是另一個機器內(nèi)存大些,我們需要一個數(shù)組能夠大些。)

#include <stdio.h>
int main()
{
    int array[ARRAY_SIZE];//這個地方并沒有指定ARRAY_SIZE的大小	
    int i = 0;
    for (i = 0; i < ARRAY_SIZE; i++)
    {
        array[i] = i;
    }
    for (i = 0; i < ARRAY_SIZE; i++)
    {
        printf("%d ", array[i]);
    }
    printf("\n");
    return 0;
}

編譯指令:

gcc -D ARRAY_SIZE=10 programe.c
條件編譯

在編譯一個程序的時候我們?nèi)绻麑⒁粭l語句(一組語句)編譯或者放棄是很方便的。因為我們由條件編譯指令

#include <stdio.h>

#define __DEBUG__

int main() {
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0; i < 10; i++) {
		arr[i] = i;
#ifdef __DEBUG__
		printf("%d ", arr[i]);
#endif //__DEBUG__
	}
	return 0;
}

常見的條件編譯指令

  1. #if 常量表達式

#endif //常量表達式由預(yù)處理器求值

  1. 過個分支的條件編譯

#if 常量表達式

#elif 常量表達式

#else

#endif

  1. 判斷是否被定義

#if defined(symbol)

#ifdef symbol

  1. 嵌套指令

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

文件包含

我們已經(jīng)知道,#include指令可以使另一個文件被編譯。就像它實際出現(xiàn)于#include指令的地方一樣。

這種替換方式很簡單:預(yù)處理器先刪除這條指令,并用包含文件的內(nèi)容替換。這樣一個源文件包含10次,那就實際編譯了10次

頭文件被包含的方式
  • 本地文件包含
#include "filename";

查找策略:現(xiàn)在源文件所在的目錄下查找,如果該頭文件未找到,編譯器就像查找?guī)旌瘮?shù)頭文件一樣在標(biāo)準(zhǔn)位置查找頭文件。如果找不到就提示編譯錯誤。

嵌套文件包含

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

這樣就會造成文件內(nèi)容的重復(fù)。

如何解決這個問題?

#pragma once

就可以避免頭文件的重復(fù)引入。

筆試題:

【C語言】程序環(huán)境和預(yù)處理,C語言,c++,c語言,算法

其他預(yù)處理指令

#error

#pragma文章來源地址http://www.zghlxwxcb.cn/news/detail-810882.html

到了這里,關(guān)于【C語言】程序環(huán)境和預(yù)處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C語言--程序環(huán)境和預(yù)處理(宏)

    C語言--程序環(huán)境和預(yù)處理(宏)

    目錄 前言 本章重點: ?1. 程序的翻譯環(huán)境和執(zhí)行環(huán)境 2. 詳解編譯+鏈接 2.1 翻譯環(huán)境?編輯 2.2 編譯本身也分為幾個階段 2.3 運行環(huán)境 3. 預(yù)處理詳解 3.1 預(yù)定義符號 3.2 #define 3.2.1 #define 定義標(biāo)識符 3.2.2 #define 定義宏 2.2.3 #define 替換規(guī)則 3.2.4 #和## ?3.2.5 帶副作用的宏參數(shù) 3.2.6 宏

    2024年02月07日
    瀏覽(18)
  • 程序環(huán)境和預(yù)處理(含C語言程序的編譯+鏈接)--2

    程序環(huán)境和預(yù)處理(含C語言程序的編譯+鏈接)--2

    文章前言: 上章我們把? ? ? 程序的翻譯環(huán)境? ? ?程序的執(zhí)行環(huán)境? ?C語言程序的編譯+鏈接? ? ?預(yù)定義符號介紹? ? 預(yù)處理指令? ?#define? ? 宏和函數(shù)的對比? ? ?預(yù)處理操作符? ? #和##的介紹 ? 的相關(guān)知識進行了梳理講解,接下來被把剩余知識? ? 命令定義? ? ?預(yù)處

    2024年02月14日
    瀏覽(31)
  • C語言-程序環(huán)境和預(yù)處理(2)--帶副作用的宏參數(shù),宏與函數(shù)的對比,#undef,條件編譯,文件包含

    C語言-程序環(huán)境和預(yù)處理(2)--帶副作用的宏參數(shù),宏與函數(shù)的對比,#undef,條件編譯,文件包含

    上一篇文章–《C語言-程序環(huán)境和預(yù)處理(1)》講述了程序的翻譯環(huán)境和執(zhí)行環(huán)境,編譯、連接,預(yù)定義符號,#define,#符號和##符號的相關(guān)知識。 鏈接: 《C語言-程序環(huán)境和預(yù)處理(1)》 本篇文章,講述帶副作用的宏參數(shù),宏與函數(shù)的對比,#undef,條件編譯,文件包含的相

    2024年02月08日
    瀏覽(28)
  • 程序環(huán)境和預(yù)處理(詳解)

    程序環(huán)境和預(yù)處理(詳解)

    ??博客主頁:?自信不孤單 ??文章專欄:C語言 ??代碼倉庫:破浪曉夢 ??歡迎關(guān)注:歡迎大家點贊收藏+關(guān)注 本文重點 代碼編譯鏈接變成可執(zhí)行程序程序的過程 掌握學(xué)習(xí)各種預(yù)處理知識 在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境: 翻譯環(huán)境,在這個環(huán)境中源代碼被

    2023年04月27日
    瀏覽(23)
  • 【C】程序環(huán)境和預(yù)處理

    【C】程序環(huán)境和預(yù)處理

    在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境。 第1種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換為可執(zhí)行的機器指令。 第2種是執(zhí)行環(huán)境,它用于實際執(zhí)行代碼。 翻譯環(huán)境我們主要解釋一下編譯和鏈接過程。 我們的源文件也就是我們的.c文件通過編譯器生成一個目標(biāo)文件(

    2024年02月16日
    瀏覽(23)
  • 程序環(huán)境和預(yù)處理(上)——“C”

    程序環(huán)境和預(yù)處理(上)——“C”

    各位CSDN的uu們你們好呀,今天小雅蘭的內(nèi)容是C語言中的程序環(huán)境和預(yù)處理這個知識點,這塊知識點是小雅蘭地C語言的最后一塊知識點了,以后可能會更新一些C語言的書籍的閱讀,比如:《C? Primer? Plus》和《C語言深度剖析》。好啦,讓我們進入程序環(huán)境和預(yù)處理的世界吧。

    2023年04月09日
    瀏覽(19)
  • 程序環(huán)境和預(yù)處理(下)——“C”

    程序環(huán)境和預(yù)處理(下)——“C”

    各位CSDN的uu們你們好呀,今天小雅蘭的內(nèi)容是程序環(huán)境和預(yù)處理的下篇知識點,那么,這篇博客寫完后,C語言的知識點就到這里就結(jié)束啦,后續(xù)會專注于刷題和讀書,也是關(guān)于C語言的,會寫一些數(shù)據(jù)結(jié)構(gòu)和C++的內(nèi)容,好啦,讓我們進入程序環(huán)境和預(yù)處理的世界吧 預(yù)處理詳解

    2023年04月16日
    瀏覽(21)
  • 程序員進階之路:程序環(huán)境和預(yù)處理

    程序員進階之路:程序環(huán)境和預(yù)處理

    ? 目錄 ? 前言 程序的翻譯環(huán)境和執(zhí)行環(huán)境 翻譯環(huán)境 運行環(huán)境 預(yù)處理(預(yù)編譯) 預(yù)定義符號 #define #define 定義標(biāo)識符 #define 定義宏 ?#define 替換規(guī)則 ?#和## ?#的作用 ##的作用 ?帶副作用的宏參數(shù) ?宏和函數(shù)對比 命名約定 ?#undef 命令行定義 條件編譯? 文件包含 ?嵌套文件包

    2024年02月16日
    瀏覽(26)
  • 015+limou+C語言深入知識——(7)編譯環(huán)境和運行環(huán)境以及預(yù)處理指令

    015+limou+C語言深入知識——(7)編譯環(huán)境和運行環(huán)境以及預(yù)處理指令

    在這個環(huán)境中,源代碼被轉(zhuǎn)化為可執(zhí)行的機器指令(二進制指令) 單文件簡易版本 多文件簡易版本 編譯鏈接詳細版本 VS2022集成IDE(windows下)的編譯器叫cl.exe,鏈接器叫l(wèi)ink.exe gcc編譯器(windows下)的幾個有關(guān)編譯環(huán)境的命令 (1)符號表會把全局變量和具有外部鏈接的函數(shù)

    2023年04月11日
    瀏覽(22)
  • 【C語言深入】深入理解程序的預(yù)處理過程

    【C語言深入】深入理解程序的預(yù)處理過程

    我們平時所寫的每一個.c文件都會經(jīng)過編譯和連接的過程之后才會形成一個可執(zhí)行程序: 今天我們就來詳細的看看編譯和連接這兩個過程的具體細節(jié)。 程序的翻譯環(huán)境與執(zhí)行環(huán)境 在ANSI C的任何一種實現(xiàn)中,存在兩個不同的環(huán)境。 第1種是翻譯環(huán)境,在這個環(huán)境中源代碼被轉(zhuǎn)換

    2023年04月08日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包