Modbus軟體開發實戰指南 之 開發自己的Modbus Poll工具 - 2

來源:互聯網
上載者:User

標籤:enter   返回   ora   興趣   rar   指定   程式   啟動   分享   

接上一篇文章的內容。

看了前面需求提到的複雜的命令列解析功能,很多人立馬開始發怵,其實大可不必。

我們都知道,Linux下的程式往往都提供了複雜的命令列參數處理機制,因為這是與

其他程式或使用者進行互動的主要手段,在這樣的情況下難能可貴的是,為了減輕開發

人員對命令列處理的負擔,Linux提供了系統函數getopt()或getopt_long()專門解析命令列參數。

 

在Linux系統中,函數getopt()/getopt_long()位於 unistd.h 系統標頭檔中,其原型分別為:

int getopt(int argc,char * const argv[],const char * optstring);

int getopt_long(int argc, char * const argv[],const char *optstring,

                const struct option *longopts, int *longindex);

其中,參數argc和argv是由主函數main()傳遞的參數個數和內容。

參數optstring 則代表欲處理的選項字串。此函數會返回在argv 中下一個的選項字母,

此字母會對應參數optstring 中的字母。如果選項字串裡的字母后接著冒號“:”,則表示還有相關的參數,

全域變數optarg 即會指向此額外參數。如果getopt()找不到符合的參數則會列印出錯資訊,並將全域

變數optopt設為“?”字元,如果不希望getopt()列印出錯資訊,則只要將全域變數opterr設為0即可。

 

參數可簡單劃分為短參數和長參數兩種類型,getopt()使用optstring所指的字串作為短參數列表,

象“1ac:d::”就是一個短參數列表。短參數的定義是一個‘-‘後面跟一個字母或數字,象-a, -b就是一個

短參數,每個數字或字母定義一個參數。

 

而長參數則形如“--debug”,前面有2個‘-‘符號,後面可添加多個字母或數字。

getopt_long()函數包含了getopt()函數的功能,並且還可以指定“長參數”(或者說長選項),

與getopt()函數對比,getopt_long()比getopt()多了兩個參數。

 

此函數的基本用法如下(Linux下):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include <stdio.h>
#include <unistd.h>

int main(int argc, int *argv[])
{
    int ch;
    opterr = 0;

    // getopt()可由getopt_long()替換
    while ((ch = getopt(argc, argv, "a:bcde")) != -1)
    {
        switch(ch)
        {
        case ‘a‘:
            printf("option a:‘%s‘\n", optarg);
            break;
        case ‘b‘:
            printf("option b :b\n");
            break;
        default:
            printf("other option :%c\n", ch);
        }
    }
    printf("optopt +%c\n", optopt);
}

以上作為參照,可見調用函數getopt()或getopt_long()可以非常方便地解析命令列。

但是,有一點遺憾的是,如此方便的函數在Windows下卻沒有提供,怎麼辦呢?當然有辦法了,

既然函數getopt()/getopt_long()是GNU C中的函數,那麼源碼可見就可以根據情況直接移植到Windows下。

說幹就幹,接下來簡要介紹一下移植方法,掌握一點新技能,如果對這部分沒有興趣,可以跳過,看後面的內容。

 

首先,訪問GNU C Library (glibc)的首頁http://www.gnu.org/software/libc/,並下載最新的glibc庫,

當前最新版是glibc-2.24.tar.gz,下載完畢並解壓。

提取加壓後的目錄\glibc-2.24\posix\下的4個源檔案getopt.h/getopt.c/getopt_int.h/

 

getopt_init.c,。

 

 

 圖 提取getopt()相關檔案

啟動Visual Studio 2015,選擇菜單【File】->【New】->【Project...】,

準備建立一個新的預設工程項目,項目類型為【Visual C++】→【Win32Console Application】。

建立新的預設工程項目完畢之後,切換到資源管理員畫面,將以上4個檔案複製到新項目所在目錄,並添加到工程項目中,。

圖 添加getopt()源檔案

檔案添加完畢之後,我們試著編譯一下看看,果不其然,檔案getopt.c出現了編譯錯誤:

getopt.c(71): fatal errorC1083: Cannot open include file: ‘gettext.h‘:No such file or directory

首先需要修改的是沒有“gettext.h”這個標頭檔的問題。修改方法為直接將其注釋掉或刪除,然後修改後面的宏定義。

將下面的原始代碼(大概在70行):

1
2
3
4
5
6

#ifdef _LIBC
# include <libintl.h>
#else
# include "gettext.h"
# define _(msgid) gettext (msgid)
#endif

修改為:

1
2
3
4
5

#ifdef _LIBC
# include <libintl.h>
#else
# define _(msgid)  (msgid)
#endif

修改完畢,繼續編譯一下看看,出現如下編譯錯誤,。

                    

圖 編譯錯誤alloca無法識別

 

錯誤的文字描述為:

getopt.c(568): warningC4013: ‘alloca‘ undefined; assumingextern returning int

error LNK2019: unresolved external symbol _allocareferenced in function __getopt_internal_r

可以發現,這裡出錯的原因是alloca這個函數沒有定義,那麼alloca函數是什麼意思呢?

原來alloca是一個記憶體配置函數,與malloc、calloc、realloc類似,但是注意一個重要的區別,

alloca函數是在棧(stack)上申請空間,用完馬上就釋放。

 

一般情況下,函數alloca包含在標頭檔malloc.h中,在某些系統中被定義為內建函式_alloca的宏定義。

既然已經知道原型了,那麼修改alloca為_alloca即可解決問題,。

 

圖 修改為_alloca解決編譯錯誤

 

繼續添加getopt_long()/getopt_long_only()的定義,這兩個函數在getopt.h檔案中聲明了,

但是其定義在getopt1.c中,可以直接將getopt1.c檔案也拿過來用,但是因為這個檔案中的內容不多,

為了減少檔案的數量,直接將其中有用的部分拷貝到getopt.c檔案中是個不錯的主意。

檔案getopt1.c中要拷貝的內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

int
getopt_long (int argc, char *const *argv, const char *options,
             const struct option *long_options, int *opt_index)
{
    return _getopt_internal (argc,argv,options,long_options,opt_index,0,0);
}

int
_getopt_long_r (int argc, char *const *argv, const char *options,
                const struct option *long_options, int *opt_index,
                struct _getopt_data *d)
{
    return _getopt_internal_r(argc,argv,options,long_options,opt_index,
                               0, d, 0);
}

/* Like getopt_long, but ‘-‘ as well as ‘--‘ can indicate a long option.
   If an option that starts with ‘-‘ (not ‘--‘) doesn‘t match a long option,
   but does match a short option, it is parsed as a short option
   instead.  */

int
getopt_long_only (int argc, char *const *argv, const char *options,
                  const struct option *long_options, int *opt_index)
{
    return _getopt_internal(argc,argv,options,long_options,opt_index,1,0);
}

int
_getopt_long_only_r (int argc, char *const *argv, const char *options,
                     const struct option *long_options, int *opt_index,
                     struct _getopt_data *d)
{
    return _getopt_internal_r(argc,argv,options,long_options,opt_index,
                               1, d, 0);
}

將以上代碼拷貝到檔案getopt.c中函數getopt()定義之後即可,修改完畢編譯,一切OK!

至此函數getopt()移植結束。經過上面的修改,可以進行一些簡單的測試進行驗證,

測試案例不用自己寫了,在檔案getopt.c和getopt1.c檔案中都有,直接拿過來用就可以。

至此,重建的4個檔案:getopt.h/getopt.c/getopt_int.h/getopt_init.c就是需要的命令列解析原始碼檔案,可以用在Windows系統下。

 

至此,針對自己開發modbus poll工具的命令列解析功能基本實現了。

接下來,將進行功能部分的程式碼分析和調試。

 

Modbus軟體開發實戰指南 之 開發自己的Modbus Poll工具 - 2

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.