# 帶你閱讀一座程式 函式拆解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。
今天就寫到這,感謝您的閱讀。