Try   HackMD

帶你閱讀一座程式 函式拆解I

tags: libmodbus

Copyright 2021, 月下麒麟


今日主角: ctx = modbus_new_rtu

Trace go
Reference: trace here

ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1);

此時已判斷完 use_backend == RTU;


Trace modbus-rtu.c

modbus_t* modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit) { modbus_t *ctx; modbus_rtu_t *ctx_rtu; //... }

前面做一些device, baud的判斷,如果有錯誤,則回傳NULL,並結束new-rtu這個任務。

ctx = (modbus_t *)malloc(sizeof(modbus_t));

配置一空間給指標變數ctx。


Trace modbus.c

void _modbus_init_common(modbus_t *ctx) { modbus_t *ctx; modbus_rtu_t *ctx_rtu; //... }

將指標變數ctx配置完的空間,賦予初值。
這邊有意思為配置變數的初值結構會對應結構定義的地方(這不是廢話嗎? 筆者希望閱讀到這能有意識到這點)
(白話文:這裡就是做初始化的地方)

另外,有兩個結構成員是沒有做初始化的,分別為
*backend 與 *backend_data


Trace modbus-rtu.c

ctx->backend = &_modbus_rtu_backend; ctx->backend_data = (modbus_rtu_t *)malloc(sizeof(modbus_rtu_t));

所以緊接著,將還沒做初始化的兩個結構成員賦予空間或對應的位址
那為什麼不將這兩個包進去 _modbus_init_common()函式呢

因為modbus區分rtu, tcp,這裡開始會呼叫不同的函式處理,故不能包進去。

&_modbus_rtu_backend
有趣的為指向struct modbus_backend_t

const modbus_backend_t _modbus_rtu_backend = {
    //...
}

那它其實會對應到 define struct _modbus_backend

typedef struct _modbus_backend { //... } modbus_backend_t;

_modbus_backend裡面原作就是裡用function pointer來呼叫對應的函式

接著,做完*ctx->backend,緊接著是 *backend_data

typedef struct _modbus_rtu { //... } modbus_rtu_t;

它被賦予的結構空間為 struct modbus_rtu_t,
其裡面就是裝一些Modbus RTU會用到的連線參數(baud, device, parity, stop_bit, data_bit)

這邊原作設計細節,在Modbus TCP就會配置不一樣的結構(modbus_tcp_t)給backend_data
(只能說原作大大神人啊,不要再佩服啦,快把文章寫完!)


都賦予完空間與位址後,還記得_modbus_init_common()函式有兩個指標變數,
那剛剛才完成一半(*ctx),還剩下(*ctx_rtu)。

ctx_rtu = (modbus_rtu_t *)ctx->backend_data;

閱讀到這裡,疑惑指標變數*ctx_rtu 已經指向 modbus_rtu_t,

哉問,那為什麼還要配置記憶體空間?

ctx->backend_data = (modbus_rtu_t *)malloc(sizeof(modbus_rtu_t)); ctx_rtu = (modbus_rtu_t *)ctx->backend_data; //... /* Device name and \0 */ ctx_rtu->device = (char *)malloc((strlen(device) + 1) * sizeof(char));

指標指向一struct,只有其位址,並不能對結構內的成員做事,
所以 ctx_rtu->device,這樣變更結構成員device給予賦值或配置,
其前提為須先配置(molloc)一記憶體空間,並且參考對象為欲存取結構成員其結構

上下交相賊,預知結果,故先設計好(你要去取得它,故先參考配置它)
此時,就可以對結構內的成員做存取操作!

結構存取方式為 指標名稱->結構成員 = 欲存取之內容

ctx_rtu->baud = baud; ctx_rtu->data_bit = data_bit; ctx_rtu->stop_bit = stop_bit; ctx_rtu->confirmation_to_ignore = FALSE; return ctx;

Summary
回傳一個已經都有各個資料的指標變數ctx。

今天就寫到這,感謝您的閱讀。