# 如何看懂Open Source : 帶你閱讀一座程式I
###### tags: `libmodbus`
Copyright 2021, [月下麒麟](https://hackmd.io/@YMont/note-catalog)
---
專案Source Code下載處-
>git clone https://github.com/stephane/libmodbus.git (參考來源)
## 概要
這份筆記主要用來記錄學習該**libmodbus**的疑問,
故於順序上會較凌亂,採用各個擊破的方式。
另外,因網路上這方面的文章較少,也想分享有關如何自學**Open Source**的方法。
(附上網路上的前輩寫的[實例研討: 從 C++ 學習 C 高級技巧](https://goodspeedlee.blogspot.com/2016/10/c-c.html))
## 什麼是Modbus
Modbus為眾多工業通訊協定中的一種,
就是讓機器用來互相溝通的一種語言。
該libmodbus就是一個開源程式碼,讓終端使用者下載到指定的機器設備上,
透由安裝與設定,就能在該機器設備上使用Modbus協定。
關於機器與通訊協定的關係,可參考下圖-

(白話例子:**一個說英語,德語的人,可以跟只會說德語的人溝通**)
這樣是不是更能明白關於通訊協定在機器上應用了呢
## 學習前的建議
建議可先閱讀三份Modbus Specification,
閱讀specification一定很枯燥乏味,但務必要耐住性子,
至少先把第一份看完,嘗試去理解Modbus的行為,
其實文件內容就是機器間的溝通規則,並不難以理解,
就跟人溝通一樣,也是滿有趣。
1.Modbus功能代碼解釋及資料格式-
[Modbus Application Protocol Specification V1.1b](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf)
2.Modbus應用於串列通訊
[Modbus over Serial Line Specification & Implementation Guide V1.02](https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf)
3.Modbus應用於TCP/IP通訊
[Modbus Message on TCP/IP Implementation Guide V1.0a](https://modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0a.pdf)
## 學習思路
1.從makefile理解安裝過程
2.從header理解有哪些函式宣告與定義
3.從unit test,可了解到設計者如何呼叫函式及實作
3-1.看printf,要印什麼東西,從輸出反推程式的意思!
4.再次閱讀Specification
(重複以上學習流程)
---

>*以上,學習方法僅供參考,畢竟每個人的學習方式不同,
>只要找到最適合自己的即可。*
>*如不想直接閱讀Modbus Specification也是可以的,
>那就跟著筆者一起摸索Open Source Code有趣的世界吧,
>一起 Trace程式碼 Go~*
## Get start
Reference:[從這裡開始瀏覽libmodbus原始碼程式](https://github.com/stephane/libmodbus/blob/master/tests/unit-test-server.c#L32)
欲認識對方的程式碼,可先從對方寫的**範例程式**或是**測試程式**開始
```c=
int main(int argc, char*argv[])
{
//...
modbus_t *ctx;
//...
```
這邊提及一下有個struct會在source code裡面大量出現,
為指標ctx指向的**modbus_t** struct,
所以這一篇幅會先認識struct與其應用。
## Question & Answer
### #Q1,認識struct
```c=
//libmodbus/tests/unit-test-server.c
modbus_t* ctx; //line 35
```
搜尋modbus_t其定義。
```c=
//libmodbus/src/modbus.h
typedef struct _modbus modbus_t; //line 155
```
發現該modbus_t為_modbus結構的別名。
接著,再搜尋_modbus其定義,會發現到它是一個匿名結構。
```c=
//libmodbus/src/modbus-private.h
struct _modbus { //line 92
/* Slave address */
int slave;
/* Socket or file descriptor */
int s;
//...
};
```
### #A1
**method 1**
```c=
typedef struct _modbus modbus_t; //typedef別名
struct _modbus {
int slave;
};
int main(){
modbus_t* ctx = (void*) malloc(sizeof(int));
//modbus_t前面不用加 struct
return 0;
}
```
**method 2,這個寫法更簡短**
```c=
typedef struct _modbus { //利用typedef與結構之member(modbus_t)合併一起
int slave;
} modbus_t ;
int main(){
modbus_t* ctx = (modbus*) malloc(sizeof(int));
//modbus_t前面不用加 struct
return 0;
}
```
**method 3,不使用typedef,較冗長**
```c=
struct _modbus{
int slave;
}modbus_t;
int main(){
struct modbus_t* ctx = (struct modbus_t*) malloc(sizeof(int));
//凡用到modbus_t的都要在前面加上"struct"
return 0;
}
```
### #Q2,理解malloc
```c=
// #1
char* ptr = (void*)malloc(4*sizeof(int));//較常看到的
// #2
modbus_t* ctx = ( modbus_t*)malloc(sizeof(modbus_t)); //變型
//請搭配Q1的struct
```
### #A2
```c=
#include <stdio.h>
#include <stdlib.h>
int main() {
char* ptr = (void*)malloc(4*sizeof(int));
printf("*ptr: %ld\n",sizeof(*ptr)); // 回傳指標ptr指向的型別(char)的大小
printf("ptr: %ld\n",sizeof(ptr)); // 指標的大小
return 0;
}
//Output
/*
*ptr: 1
ptr: 8
*/
```
誠如上述,這個malloc用法較為常見
在64位元架構下,指標大小都為8 bytes(64 bits / 8 bits )。
32位元之指標大小則為4 bytes。
```c=
#include <stdio.h>
#include <stdlib.h>
typedef struct _modbus{
int a; //int size is 4
int b; // 4
char c; // 1
char d; // 1
float e; // 4
float f; // 4
} modbus_t;
int main(){
modbus_t* ptr = (modbus_t*) malloc(sizeof(modbus_t));
printf("*ptr: %ld\n",sizeof(*ptr));
printf("ptr: %ld\n" ,sizeof(ptr));
printf("modbus_t*: %ld\n",sizeof(modbus_t*));
printf("modbus_t: %ld\n" ,sizeof(modbus_t));
return 0;
}
//Output
/*
*ptr: 20
ptr: 8
modbus_t*: 8
modbus_t: 20
*/
```
**\*ptr**為指標ptr的型別modbus_t的大小。
**ptr**為指標ptr本身的大小 (**白話,就是指標大小**)。
**modbus_t\*** 為指標modbus_t本身的大小 (**白話,就是指標大小**)。
**modbus_t**為_modbus結構其所有成員加總的大小。
(如加總大小超過或不足4的倍數,得到的結構大小有所不同,筆者這部分涉獵不深,故無法詳細描述)
另外,[malloc](https://www.cplusplus.com/reference/cstdlib/malloc/)語法設計上會回傳指向一個不指定型別的指標
>void* malloc (size_t size);
故再實際應用上,需要在加上欲指向之型別,詳細解釋可參考[C_CPP看板](https://www.ptt.cc/bbs/C_and_CPP/M.1430127985.A.4B8.html)
>modbus_t *ctx;
>ctx = (modbus_t *)malloc(sizeof(modbus_t));
## 補充
```c=
int att = 10;
int *ppt;
ppt = &att;
printf("ppt: %lu\n",sizeof(ppt));
printf("*ppt: %lu\n",sizeof(*ppt));
printf("address of ppt: %p\n", ppt);
printf("value of ppt: %d\n", *ppt);
//Output
// ppt: 8
// *ppt: 4
// address of ppt: 0x7fff021c8598
// value of ppt: 10
```