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

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

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

嵌入式C語言中內(nèi)聚和耦合的定義淺析

工程師進(jìn)階筆記 ? 來源:CSDN ? 2023-11-25 16:15 ? 次閱讀

1 - 原理篇

耦合,是指模塊之間盡可能的使其獨(dú)立存在,模塊之間不產(chǎn)生聯(lián)系不可能,但模塊與模塊之間的接口應(yīng)該盡量少而簡單。這樣,高內(nèi)聚從整個程序中每一個模塊的內(nèi)部特征角度,低耦合從程序中各個模塊之間的關(guān)聯(lián)關(guān)系角度,對我們的設(shè)計(jì)提出了要求。

程序設(shè)計(jì)和軟件工程發(fā)展過程中產(chǎn)生的很多技術(shù)、設(shè)計(jì)原則,都可以從內(nèi)聚和耦合的角度進(jìn)行解讀。作為C語言程序設(shè)計(jì)的初學(xué)者,結(jié)合當(dāng)前對于函數(shù)的理解可達(dá)到的程度,我們探討一下如何做到高內(nèi)聚低耦合。

針對低耦合。耦合程度最低的是非直接耦合,指兩個函數(shù)之間的聯(lián)系完全是通過共同的調(diào)用函數(shù)的控制和調(diào)用來實(shí)現(xiàn)的,耦合度最弱,函數(shù)的獨(dú)立性最強(qiáng)。但一組函數(shù)之間沒有數(shù)據(jù)傳遞顯然不現(xiàn)實(shí),次之追求數(shù)據(jù)耦合,調(diào)用函數(shù)和被調(diào)用函數(shù)之間只傳遞簡單的數(shù)據(jù)參數(shù),例如采用值傳遞方式的函數(shù)。

有些函數(shù)數(shù)在調(diào)用時,利用形式參數(shù)傳地址的方式,在函數(shù)體內(nèi)通過指針可以修改其指向的作用域以外的存儲單元,這構(gòu)成了更強(qiáng)的耦合,稱為特征耦合,在這里,使函數(shù)之間產(chǎn)生聯(lián)系的是地址這樣的特征標(biāo)識。另外,有兩個函數(shù)可能會打開同一個文件進(jìn)行操作,這也構(gòu)成了特征耦合的一種形式。

更強(qiáng)的耦合是外部耦合,這里,一組模塊都訪問同一全局變量,而且不通過參數(shù)表傳遞該全局變量的信息,當(dāng)發(fā)現(xiàn)程序執(zhí)行結(jié)果異常時,很難定位到是在哪個函數(shù)中出了差錯。不少初學(xué)者覺得參數(shù)傳遞麻煩,將要處理的數(shù)據(jù)盡可能地定義為全局變量,這樣,函數(shù)之間的接口簡單了,但形成的是耦合性很強(qiáng)的結(jié)構(gòu)。

在C語言中,還可以通過靜態(tài)局部變量,在同一個程序的兩次調(diào)用之間共享數(shù)據(jù),這也可以視為是一種外部耦合,只不過靜態(tài)局部變量的作用域限于函數(shù)內(nèi)部,其影響也只在函數(shù)內(nèi)部,耦合程度比使全局變量也還是弱很多。由此,我們可以理解前述在使用全局變量、靜態(tài)局部變量時提出的“用在合適的時候,不濫用”的原則。

針對高內(nèi)聚。內(nèi)聚程度最高的是功能內(nèi)聚,模塊內(nèi)所有元素的各個組成部分全部都為完成同一個功能而存在,共同完成一個單一的功能,模塊已不可再分。這樣的函數(shù)功能非常清晰、明確,一般出現(xiàn)在程序結(jié)構(gòu)圖的較低被調(diào)用的層次上。

次之的是順序內(nèi)聚,一個函數(shù)中各個處理元素和同一個功能密切相關(guān),通常前一個處理元素的輸出是后一個處理元素的輸入。對于這樣的函數(shù),如果不致于產(chǎn)生高耦合的話,可以分開兩個函數(shù)實(shí)現(xiàn)。

有的函數(shù),其中的不同處理功能僅僅是由于都訪問某一個公用數(shù)據(jù)而發(fā)生關(guān)聯(lián),這稱為通信內(nèi)聚和信息內(nèi)聚,內(nèi)聚程度進(jìn)一步下降。內(nèi)聚程度再低的情況就不再一一列舉,最差的偶然內(nèi)聚中,一個函數(shù)內(nèi)的各處理元素之間沒有任何聯(lián)系,只是偶然地被湊到一起。

可以想像這樣的模塊東一榔頭西一錘子,類似一個毫無凝聚力的團(tuán)伙,對應(yīng)的是低質(zhì)量??傊?,在解決問題劃分函數(shù)時,要遵循“一個函數(shù),一個功能”的原則,盡可能使模塊達(dá)到功能內(nèi)聚。

要做到高內(nèi)聚低耦合,重點(diǎn)是要在寫代碼之前花些時間做好設(shè)計(jì)。在下面的例子中,將討論結(jié)合具體的問題,如何將以上的因素考慮進(jìn)去。

2-示例篇

本例受裘宗燕老師《從問題到程序——程序設(shè)計(jì)與C語言引論》啟發(fā)。

任務(wù):輸出200以內(nèi)的完全平方數(shù)(一個數(shù)如果是另一個整數(shù)的完全平方,那么我們就稱這個數(shù)為完全平方數(shù),也叫做平方數(shù)),要求每隔5個數(shù)據(jù)要輸出一個換行。

解決方案及點(diǎn)評對于這個簡單任務(wù),我們在一個main函數(shù)中完成了任務(wù)。程序如方案1:


//方案1:內(nèi)聚性較高的單模塊實(shí)現(xiàn)方案
#include 
int main()
{
    int m, num=0;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d ", m * m);
        num++;
        if (num%5==0)
            printf("
");
    }
    return 0;
}

由于任務(wù)本身簡單,將之在一個main函數(shù)中實(shí)現(xiàn)后,這個函數(shù)的內(nèi)聚程度接近功能內(nèi)聚,已經(jīng)相當(dāng)高了,就任務(wù)本身,不需再進(jìn)行分解。為使讀者能深入理解模塊質(zhì)量方面的技術(shù),我們將試圖將內(nèi)聚程序再提高一些,然后考察耦合程度不同的各種解決方案。

要提高上面解決方案中函數(shù)(僅main一個函數(shù))的內(nèi)聚程度,我們考察程度的功能“找出完全平方數(shù)并輸出”——“找出完全平方數(shù)”和“輸出”這本身就是兩個功能,再細(xì)分輸出時還有“要求5個數(shù)據(jù)在一行”的要求,這些功能的實(shí)現(xiàn)細(xì)節(jié)都在一個函數(shù)當(dāng)中,可見是有余地再提高內(nèi)聚程度的。

在實(shí)現(xiàn)的應(yīng)用中,幾乎所有的處理都可以分解為“輸入-計(jì)算-輸出”的模式,優(yōu)秀的解決方案往往至少要將這三個模塊都獨(dú)立出來,對于“計(jì)算”模塊而言,其內(nèi)部不再包括輸入輸出,專門接受輸入的數(shù)據(jù),計(jì)算完成后返回結(jié)果即可。當(dāng)然,對于復(fù)雜的問題,在各個環(huán)節(jié)上可能還需要再做分解。

下面,我們探討將“找出完全平方數(shù)輸出”和“每5個數(shù)據(jù)后換行”分開實(shí)現(xiàn)的方案。這樣的分解有助于提高內(nèi)聚性,與此同時,分解后的兩個模塊間的耦合程度,成為我們要關(guān)注的焦點(diǎn)。

現(xiàn)在將“找出完全平方數(shù)并輸出”的功能仍放在main函數(shù)中(獨(dú)立成為單獨(dú)的函數(shù)也可以,但不必要了),而“每5個數(shù)據(jù)后換行”的功能,設(shè)計(jì)一個名稱為format的函數(shù),它每調(diào)用一次就輸出一個空格作為兩個完全平方數(shù)間的分隔,而每調(diào)用到第5次時,輸出的是一個換行。

這兩個模塊之間,需要有一個“現(xiàn)在是第幾次調(diào)用”的信息需要傳遞,不可能用耦合程度最松散的非直接耦合.我們考慮數(shù)據(jù)耦合,用簡單形式參數(shù)傳值,得到方案2。

//方案2:一個耦合度低,但不能完成功能要求的解決方案
#include 
void format(int);
int main()
{
    int m, num=0;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d", m * m);
        format(num);
    }
    return 0;
}
void format(int n)
{
    n++;
    if (n%5==0)
        printf("
");
    else
        printf(" ");
    return;
}

在這個程序結(jié)構(gòu)中,format與main函數(shù)的耦合程度為數(shù)據(jù)耦合。在main中定義了局部變量num,在一次都未輸出時,置初值為0是合理的。在調(diào)用format時,將num傳遞來的表示第幾次輸出(第幾個完全平方數(shù))的形式參數(shù)n,n自增1,然后再控制輸出空格或換行。

然而分析和運(yùn)行程序發(fā)現(xiàn),“每隔5個數(shù)據(jù)輸出一個換行”的功能并未實(shí)現(xiàn)。因?yàn)樾问絽?shù)n在函數(shù)format內(nèi)的改變對應(yīng)的實(shí)在參數(shù)num占不同的內(nèi)存空間,n++修改的結(jié)果,對num無任何的影響,導(dǎo)致了在下一次調(diào)用時,丟失了“輸出的是第幾個”的重要信息。

一個補(bǔ)救的方法,是由format將變化后的n值作為返回值,再傳回給main函數(shù),得到如下方案3的程序:

//方案3:利用了返回值使耦合度增大,但功能得以實(shí)現(xiàn)的方案
#include 
int format(int);
int main()
{
    int m, num=0;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d", m * m);
        num = format(num);
    }
    return 0;
}
int format(int n)
{
    n++;
    if (n%5==0)
        printf("
");
    else
        printf(" ");
    return n;
}

維持原函數(shù)返回值為void,而將參數(shù)改為傳地址,得到下面的方案4。這個方案的耦合度更高一些,但功能還是能夠?qū)崿F(xiàn)的。

//方案4:傳地址實(shí)現(xiàn)功能的方案,耦合度更大
#include 
void format(int*);
int main()
{
    int m, num=0;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d", m * m);
        format(&num);
    }
    return 0;
}
void format(int *p)
{
    (*p)++;
    if ((*p)%5==0)
        printf("
");
    else
        printf(" ");
    return;
}

一定有人想到了用全局變量的解決方案。這樣,可以將num定義為全局變量,num的生存周期不再依賴于函數(shù)調(diào)用,其值也能在函數(shù)的調(diào)用之間保持不變(只要其間沒有另外給它賦值),從而可以完成傳遞信息的任務(wù)。這時,format因?yàn)闊o需參數(shù)傳遞,可以設(shè)計(jì)為無參函數(shù),得到如下方案5的程序:

//方案5:耦合度最高的全局變量方案
#include 
void format();
int num=0;
int main()
{
    int m ;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d", m * m);
        format();
    }
    return 0;
}
void format()
{
    num++;
    if (num%5==0)
        printf("
");
    else
        printf(" ");
    return;
}

這是解決這個問題的耦合程度最高的一個方案。將num定義為外部變量,意味著如果還有其他函數(shù),num是可以被任何函數(shù)修改的,當(dāng)發(fā) format 計(jì)數(shù)錯誤時,尋找錯誤困難,而修改后又可能會帶來其他地方的錯誤。在這么一個短小的程序中,這種方案可能尚可接受,當(dāng)程度的規(guī)模稍變大,可能帶來的問題必須高度重視。因此,在實(shí)際應(yīng)用中,強(qiáng)調(diào)全局變量要慎用(不是不用)。

考慮到num是在format中應(yīng)用的私用數(shù)據(jù)——只有format才關(guān)心這到底是第幾個數(shù)據(jù),main本來都不用關(guān)心的。這樣,可以考慮將num定義為format中的局部靜態(tài)變量,得到方案6的程序:

//方案6:用靜態(tài)局部變量,耦合度偏高但封裝性最好的方案
#include 
void format();
int main()
{
    int m ;
    for (m = 1; m * m <= 200; m++)
    {
        printf("%d", m * m);
        format();
    }
    return 0;
}
void format()
{
    static int num=0;
    num++;
    if (num%5==0)
        printf("
");
    else
        printf(" ");
    return;
}

在這里,靜態(tài)局部變量num的作用域是局部的,定義在函數(shù)體里,封裝性在所有方案里是最好的,從而能保證信息的隱蔽性,避免其他函數(shù)無意的越權(quán)訪問;

不過,num的生存期是全局的,可以跨越函數(shù)的不同次調(diào)用,在兩次調(diào)用間傳遞信息,耦合程度(自己和自己的耦合)要高一些,

但使main函數(shù)和format函數(shù)的耦合達(dá)到了最理想的程度,既保證了功能的正確,又保證了局部數(shù)據(jù)的安全性,表現(xiàn)出靜態(tài)局部變量的優(yōu)勢。

綜上所述,在解決一個問題時,存在著諸多的方案。方案1可以接受,但希望提高內(nèi)聚性而做出改進(jìn);方案2用簡單的參數(shù)傳值方式實(shí)現(xiàn)耦合程度低,但很可惜不能完成功能;在其他方案中,對于這個問題,選擇的優(yōu)先順序是:

方案6、方案3 > 方案4 > 方案5

建議讀者回顧前面的內(nèi)容,想一想這樣排序的理由。

在上述探討各個方案的過程中,我們應(yīng)該體會到在程序設(shè)計(jì)能力提高的過程中,不斷地學(xué)習(xí)新的技術(shù),懂得新的評判標(biāo)準(zhǔn),這也就是一個不斷拓寬眼蜀的過程。

在稍后的練習(xí)中,不妨多想一些方案,也能夠從專業(yè)的角度評判方案的優(yōu)劣,最終做到的,就是出手就是最佳方案的專業(yè)水平。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5086

    文章

    19141

    瀏覽量

    305925
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7605

    瀏覽量

    137050
  • 耦合器
    +關(guān)注

    關(guān)注

    8

    文章

    725

    瀏覽量

    59753
  • 靜態(tài)變量
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    6670

原文標(biāo)題:嵌入式 C 語言,內(nèi)聚和耦合的定義。

文章出處:【微信號:工程師進(jìn)階筆記,微信公眾號:工程師進(jìn)階筆記】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C語言中定義的應(yīng)用

    C語言中,宏定義是一種預(yù)處理指令,用于在代碼中定義和使用常量、函數(shù)或代碼片段的替代。
    發(fā)表于 08-17 15:33 ?865次閱讀

    C語言入門書籍《嵌入式Linux C語言程序設(shè)計(jì)基礎(chǔ)教程》全本下載??!

    的指針。第8章主要講解了嵌入式Linux C語言的函數(shù)。第9章主要介紹了嵌入式Linux C語言中
    發(fā)表于 03-02 17:09

    嵌入式C語言C語言的區(qū)別

    嵌入式C語言C語言的區(qū)別:最常用的系統(tǒng)編程語言C
    發(fā)表于 10-27 06:52

    嵌入式C語言中__I,__O,__IO的相關(guān)資料下載

    嵌入式C語言中__I,__O,__IO簡介__I,__O,__IO在代碼中的定義這是ST庫里面的宏定義,
    發(fā)表于 12-15 06:23

    嵌入式SQL語言概述

    嵌入式SQL概述嵌入式SQL語言將SQL語言嵌入到某一種高級語言中使用這種高級
    發(fā)表于 12-21 06:55

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

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

    C語言中的高內(nèi)耦合講解

    編程時,我們講究的是高內(nèi)耦合,在協(xié)同開發(fā)、代碼移植、維護(hù)等環(huán)節(jié)都起到很重要的作用。 一、原理篇而低耦合,是指模塊之間盡可能的使其獨(dú)立存在,模塊之間不產(chǎn)生聯(lián)系不可能,但模塊與模塊之間
    的頭像 發(fā)表于 08-16 14:06 ?2335次閱讀

    標(biāo)準(zhǔn)c語言嵌入式,嵌入式C語言C語言的區(qū)別

    嵌入式C語言C語言的區(qū)別:最常用的系統(tǒng)編程語言C
    發(fā)表于 10-20 14:06 ?6次下載
    標(biāo)準(zhǔn)<b class='flag-5'>c</b><b class='flag-5'>語言</b>與<b class='flag-5'>嵌入式</b>,<b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>語言</b>與<b class='flag-5'>C</b><b class='flag-5'>語言</b>的區(qū)別

    嵌入式C語言中volatile關(guān)鍵字

    volatile06. 附錄01. volatile概述volatile是C語言中的一個關(guān)鍵字。將變量定義為volatile就表示告訴編譯器這個變量可能會被竟想不到地改變,在這種情況下,編譯器就不會去假設(shè)這個變量的值了,及優(yōu)化器
    發(fā)表于 10-21 10:21 ?6次下載
    【<b class='flag-5'>嵌入式</b>】<b class='flag-5'>C</b><b class='flag-5'>語言中</b>volatile關(guān)鍵字

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

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

    嵌入式C語言知識總結(jié)

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

    簡單介紹嵌入式C語言中常用的位操作

    嵌入式C語言中,使用位操作程序有很好的可讀性。以下就簡單介紹以下常用的位操作。
    的頭像 發(fā)表于 02-23 10:36 ?1031次閱讀

    嵌入式C語言中堆和棧的區(qū)別

    嵌入式C語言中,堆和棧都是用來存儲變量的內(nèi)存區(qū)域,但它們在存儲和使用變量方面有很大的區(qū)別。
    的頭像 發(fā)表于 04-14 11:45 ?1421次閱讀

    嵌入式C語言之堆和棧介紹

    嵌入式C語言中,堆和棧都是用來存儲變量的內(nèi)存區(qū)域,但它們在存儲和使用變量方面有很大的區(qū)別。
    的頭像 發(fā)表于 05-20 15:04 ?2958次閱讀

    什么是__attribute__?嵌入式C代碼屬性怎么定義?

    嵌入式開發(fā),離不開 C 語言,C語言中有很多語法會直接或間接影響你代碼的質(zhì)量,下面就來講講__attribute__ 關(guān)鍵字的用法。
    的頭像 發(fā)表于 10-13 15:55 ?6709次閱讀
    什么是__attribute__?<b class='flag-5'>嵌入式</b><b class='flag-5'>C</b>代碼屬性怎么<b class='flag-5'>定義</b>?