# 帶你閱讀一座程式 函式拆解I ###### tags: `libmodbus` Copyright 2021, [月下麒麟](https://hackmd.io/@YMont/note-catalog) --- ## 今日主角: **ctx = modbus_new_rtu** **Trace go** Reference: [trace here](https://github.com/stephane/libmodbus/blob/master/tests/unit-test-server.c#L66) ```c= ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); ``` 此時已判斷完 use_backend == RTU; --- Trace modbus-rtu.c ```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這個任務。 ```c= ctx = (modbus_t *)malloc(sizeof(modbus_t)); ``` 配置一空間給指標變數ctx。 --- Trace modbus.c ```c= void _modbus_init_common(modbus_t *ctx) { modbus_t *ctx; modbus_rtu_t *ctx_rtu; //... } ``` 將指標變數ctx配置完的空間,賦予初值。 這邊有意思為配置變數的初值結構會對應結構定義的地方(~~這不是廢話嗎?~~ 筆者希望閱讀到這能有意識到這點) (白話文:這裡就是做初始化的地方) 另外,有兩個結構成員是沒有做初始化的,分別為 \*backend 與 \*backend_data --- Trace modbus-rtu.c ```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** ```c const modbus_backend_t _modbus_rtu_backend = { //... } ``` 那它其實會對應到 define struct **\_modbus_backend** ```c= typedef struct _modbus_backend { //... } modbus_backend_t; ``` 在 **\_modbus_backend**裡面原作就是裡用**function pointer**來呼叫對應的函式 接著,做完\*ctx->backend,緊接著是 **\*backend_data** ```c= 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**)。 ```c= ctx_rtu = (modbus_rtu_t *)ctx->backend_data; ``` 閱讀到這裡,疑惑指標變數\*ctx_rtu 已經指向 modbus_rtu_t, >哉問,那為什麼還要配置記憶體空間? ```c= 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)一記憶體空間,並且**參考對象為欲存取結構成員其結構** >上下交相賊,預知結果,故先設計好(你要去取得它,故先參考配置它) >此時,就可以對結構內的成員做存取操作! 結構存取方式為 指標名稱->結構成員 = 欲存取之內容 ```c= 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。 今天就寫到這,感謝您的閱讀。