简体   繁体   English

C中的自定义命令行参数

[英]Customized command-line arguments in C

I'm currently learning C by working through K&R's The C Programming Language , and have reached the point in the book where command-line arguments are discussed. 我目前正在通过K&R的The C Programming Language学习C,并且已经达到了本书中讨论命令行参数的地步。 In the book, the main routine would be written something like this: 在这本书中,主要例程将被编写为以下内容:

int main(int argc, char *argv[])
{
    do something
}

From my understanding, at some point the number of arguments passed to the program must be counted and stored in argc . 据我了解,在某些时候必须计算传递给程序的参数数量并将其存储在argc Also, the arguments themselves must be stored, and pointers to the first characters of each are stored in the array argv , where argv[0] is a pointer to the name of the command and argv[argc] is a null pointer. 另外,必须存储参数本身,并且将每个参数的前一个字符的指针存储在数组argv ,其中argv[0]是指向命令名称的指针,而argv[argc]是空指针。 These steps can't just magically occur, this behaviour must be defined somewhere! 这些步骤不仅可以神奇地发生,还必须在某个地方定义此行为!

As an example, imagine that I want to store the first character of each argument passed to the program, firstc , and discard the remainder of that argument (let's pretend that I had a really, really good reason for doing this). 举个例子,假设我想存储传递给程序的每个参数的第一个字符firstc ,并丢弃该参数的其余部分(假设我有这样做的一个非常非常好的理由)。 I could write main() like so: 我可以这样写main():

int main(char firstc[])
{
    do something
}

Clearly, this can already be done quite easily with the default argc and argv , and I wouldn't actually do it in practice. 显然,使用默认的argcargv已经可以很容易地做到这一点,而实际上我实际上不会这样做。 I can't even imagine a scenario in which this would actually be necessary, but I'm curious to know if it's possible. 我什至无法想象实际需要这样做的情况,但是我很好奇是否有可能。

So my (entirely theoretical, completely impractical) question is this: is it possible to define my own behaviour for the command line arguments? 因此,我的问题(完全是理论上的,完全不切实际的)是这样的:是否可以为命令行参数定义我自己的行为? If it is, how would one go about doing so? 如果是这样,人们将如何做呢? If it's relevant, I'm using Ubuntu 16.04 and the GNOME Terminal. 如果相关,我正在使用Ubuntu 16.04和GNOME Terminal。

PS PS

I just realized while writing this question that it is entirely possible (perhaps probable) that the C script is completely blind to what's going on outside, and that the terminal emulator is what prepares the command-line arguments for the C program. 我只是在写这个问题时才意识到,C脚本完全有可能(也许很可能)完全看不到外部发生的事情,而终端仿真器正是为C程序准备命令行参数的原因。

The setup of arguments is not actually within the purview of the C standard, it simply dictates the allowable forms of main that you can use. 参数的设置实际上不在C标准的范围之内,它只是指示可以使用的main的允许形式。 There are two canonical forms of this (assuming a hosted implementation), one being the argc/argv option, the other being the void option (although note that an implementation is free to provide others). 有两种规范形式(假设是托管实现),一种是argc/argv选项,另一种是void选项(尽管请注意,一个实现可以自由提供其他实现)。

Typically, there is code that runs before main is called, such as from startup code in an object file like crt0.o . 通常,有一些代码调用main 之前运行,例如从诸如crt0.o类的目标文件中的启动代码运行。

However, as stated, the standard doesn't dictate anything that happens at that stage, it's the responsibility of the "environment" to set up things correctly so that main can be called. 但是,如前所述,该标准并没有规定在该阶段发生的任何事情,这是“环境”的责任,必须正确设置事物以便可以调用main

In terms of doing what you request, I suspect the easiest solution would be to provide a main taking the canonical form and simply call a myMain with the first character of each argument, though you would probably need to intelligently handle any number of arguments that may be given to main . 就您的要求而言,我怀疑最简单的解决方案是提供一个采用规范形式的main并简单地使用每个参数的第一个字符调用myMain ,尽管您可能需要智能地处理可能被赋予main

An example follows which can handle between one and three arguments: 下面的示例可以处理一个到三个参数:

#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;
}

The operating system is the one that passes the number of arguments and the arguments themselves from the command line to the C program. 操作系统是一种将参数数量和参数本身从命令行传递到C程序的系统。

The function main is not picky about its arguments. 函数main对其参数并不挑剔。 You can get no argument at all, you can get only argc , and you can get both argc and argv . 您根本没有参数,只能获取argc ,并且可以同时获取argcargv

You can even get 3 or 4 arguments with whatever types you want, but they will contain garbage. 您甚至可以使用任意类型获得3或4个参数,但是它们将包含垃圾。 The operating system will always pass the number of arguments and their names as an int and an array of pointers to strings. 操作系统将始终将参数的数目及其名称作为整数和指向字符串的指针数组传递。

Your main() declaration does not actually define what parameters you get. 您的main()声明实际上并未定义您获得的参数。 That is the responsibility of the program's environment: the operating system and the calling program, usually the command line processor. 这是程序环境的责任:操作系统和调用程序,通常是命令行处理器。

The caller (typically a shell program) prepares parameters and passes them to appropriate operating system's routine for the program to be called. 调用者(通常是shell程序)准备参数,并将其传递给要调用的程序的相应操作系统例程。 The OS routine prepares those data for a callee, typically on the stack, and makes a jump into your program's entry point, which then follows to the main function. OS例程通常在堆栈上为被调用者准备这些数据,然后跳入程序的入口点,然后进入main函数。

Your main() declaration just declares what your main expects on the stack, which indirectly defines how you can use those data, but not what they are. 您的main()声明只是声明您的main在堆栈上的期望 ,它间接定义了如何使用这些数据,但没有定义它们是什么。 That's also why you can declare main without parameters as main(void) – that simply means 'whatever is passed to me, I'll ignore it anyway'. 这也是为什么你可以声明main不带参数作为main(void) -这仅仅意味着“无论是传给我,无论如何,我会忽略它。

There are standards (like ANSI C, C89, etc.), that provide main rules and set set of restrictions, and there are agreements, that do not violate the standards and provide you some possibility. 有一些标准(例如ANSI C,C89等)提供了主要规则和一组限制,还有一些协议没有违反这些标准并为您提供了一定的可能性。

Fist, I have one more example for you: 拳头,我再为您提供一个例子:

#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;
}

Just try and see how this third argument of main can be useful. 只是尝试看看main第三个参数如何有用。

Also, I want to explain my approach to command line arguments processing. 另外,我想解释一下我的命令行参数处理方法。 I make ParseCommandLine (or EvaluateParameters ) and call it at the beginning of main . 我创建ParseCommandLine (或EvaluateParameters )并在main的开头调用它。 That function analyze strings from command line and store all settings for further convenient usage. 该函数从命令行分析字符串并存储所有设置,以进一步方便使用。 Eg if I expect my program to be run as 例如,如果我希望我的程序运行为

  prog.exe -i input_file_name -o output_file_name -e

I will do something like: 我会做类似的事情:

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM