[英]Customized command-line arguments in C
我目前正在通過K&R的The C Programming Language學習C,並且已經達到了本書中討論命令行參數的地步。 在這本書中,主要例程將被編寫為以下內容:
int main(int argc, char *argv[])
{
do something
}
據我了解,在某些時候必須計算傳遞給程序的參數數量並將其存儲在argc
。 另外,必須存儲參數本身,並且將每個參數的前一個字符的指針存儲在數組argv
,其中argv[0]
是指向命令名稱的指針,而argv[argc]
是空指針。 這些步驟不僅可以神奇地發生,還必須在某個地方定義此行為!
舉個例子,假設我想存儲傳遞給程序的每個參數的第一個字符firstc
,並丟棄該參數的其余部分(假設我有這樣做的一個非常非常好的理由)。 我可以這樣寫main():
int main(char firstc[])
{
do something
}
顯然,使用默認的argc
和argv
已經可以很容易地做到這一點,而實際上我實際上不會這樣做。 我什至無法想象實際需要這樣做的情況,但是我很好奇是否有可能。
因此,我的問題(完全是理論上的,完全不切實際的)是這樣的:是否可以為命令行參數定義我自己的行為? 如果是這樣,人們將如何做呢? 如果相關,我正在使用Ubuntu 16.04和GNOME Terminal。
PS
我只是在寫這個問題時才意識到,C腳本完全有可能(也許很可能)完全看不到外部發生的事情,而終端仿真器正是為C程序准備命令行參數的原因。
參數的設置實際上不在C標准的范圍之內,它只是指示可以使用的main
的允許形式。 有兩種規范形式(假設是托管實現),一種是argc/argv
選項,另一種是void
選項(盡管請注意,一個實現可以自由提供其他實現)。
通常,有一些代碼在調用main
之前運行,例如從諸如crt0.o
類的目標文件中的啟動代碼運行。
但是,如前所述,該標准並沒有規定在該階段發生的任何事情,這是“環境”的責任,必須正確設置事物以便可以調用main
。
就您的要求而言,我懷疑最簡單的解決方案是提供一個采用規范形式的main
並簡單地使用每個參數的第一個字符調用myMain
,盡管您可能需要智能地處理可能被賦予main
。
下面的示例可以處理一個到三個參數:
#include <stdio.h>
int myMain0(void) {
printf ("myMain0\n");
return 0;
}
int myMain1(char p1) {
printf ("myMain1 [%c]\n", p1);
return 0;
}
int myMain2(char p1, char p2) {
printf ("myMain2 [%c] [%c]\n", p1, p2);
return 0;
}
int main(int argc, char *argv[]) {
switch (argc) {
case 1: return myMain0();
case 2: return myMain1(argv[1][0]);
case 3: return myMain2(argv[1][0], argv[2][0]);
}
printf ("Invalid argument count of %d\n", argc - 1);
return 1;
}
操作系統是一種將參數數量和參數本身從命令行傳遞到C程序的系統。
函數main
對其參數並不挑剔。 您根本沒有參數,只能獲取argc
,並且可以同時獲取argc
和argv
。
您甚至可以使用任意類型獲得3或4個參數,但是它們將包含垃圾。 操作系統將始終將參數的數目及其名稱作為整數和指向字符串的指針數組傳遞。
您的main()
聲明實際上並未定義您獲得的參數。 這是程序環境的責任:操作系統和調用程序,通常是命令行處理器。
調用者(通常是shell程序)准備參數,並將其傳遞給要調用的程序的相應操作系統例程。 OS例程通常在堆棧上為被調用者准備這些數據,然后跳入程序的入口點,然后進入main
函數。
您的main()
聲明只是聲明您的main
在堆棧上的期望 ,它間接定義了如何使用這些數據,但沒有定義它們是什么。 這也是為什么你可以聲明main
不帶參數作為main(void)
-這僅僅意味着“無論是傳給我,無論如何,我會忽略它。
有一些標准(例如ANSI C,C89等)提供了主要規則和一組限制,還有一些協議沒有違反這些標准並為您提供了一定的可能性。
拳頭,我再為您提供一個例子:
#include <stdio.h>
int main(int argc, char * argv[], char * envs[])
{
int i = 1;
while (envs[i] != NULL)
{
printf("%d : %s\n", i, envs[i]);
i++;
}
return 0;
}
只是嘗試看看main
第三個參數如何有用。
另外,我想解釋一下我的命令行參數處理方法。 我創建ParseCommandLine
(或EvaluateParameters
)並在main
的開頭調用它。 該函數從命令行分析字符串並存儲所有設置,以進一步方便使用。 例如,如果我希望我的程序運行為
prog.exe -i input_file_name -o output_file_name -e
我會做類似的事情:
#include <string.h>
#include <stdio.h>
#define FNAME_LEN 20
struct settings
{
char inpFName[FNAME_LEN];
char outFName[FNAME_LEN];
bool isEncoded;
} globalSettings;
bool ParseCommandLine(int argc, char * argv[])
{
int c;
for (int c = 1; c < argc; c += 2)
{
if (!strcmp(argv[c], "-i") && c < argc - 1)
{
strncpy(globalSettings.inpFName, argv[c + 1], FNAME_LEN - 1);
continue;
}
if (!strcmp(argv[c], "-o") && c < argc - 1)
{
strncpy(globalSettings.outFName, argv[c + 1], FNAME_LEN - 1);
continue;
}
if (!strcmp(argv[c], "-e"))
{
globalSettings.isEncoded = true;
c--;
continue;
}
}
// rules to check mandatory values
if (strlen(globalSettings.inpFName) == 0 || strlen(globalSettings.outFName) == 0)
{
return false;
}
return true;
}
int main(int argc, char * argv[])
{
if (ParseCommandLine(argc, argv))
{
// do something
}
else
{
// explain how to run program
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.