# 如何看懂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協定。 關於機器與通訊協定的關係,可參考下圖- ![](https://i.imgur.com/LU1JOMe.png) (白話例子:**一個說英語,德語的人,可以跟只會說德語的人溝通**) 這樣是不是更能明白關於通訊協定在機器上應用了呢 ## 學習前的建議 建議可先閱讀三份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 (重複以上學習流程) --- ![](https://i.imgur.com/BuWQSjD.png) >*以上,學習方法僅供參考,畢竟每個人的學習方式不同, >只要找到最適合自己的即可。* >*如不想直接閱讀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 ```