C

时间:2016-08-18 04:59:35

标签: c

我目前正在通过K& R的编程语言学习C语言,并且已经达到书中讨论命令行参数的要点。在本书中,主要例程将写成如下:

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

根据我的理解,在某些时候,必须计算传递给程序的参数数量并将其存储在argc中。此外,必须存储参数本身,并且指向每个参数的指针存储在数组argv中,其中argv[0]是指向命令名称的指针,argv[argc]是空指针。这些步骤不可能神奇地发生,必须在某处定义此行为!

作为一个例子,假设我想存储传递给程序firstc的每个参数的第一个字符,并丢弃该参数的其余部分(让我们假装我真的,这样做的理由很充分)。我可以像这样编写main():

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

显然,使用默认argcargv已经很容易做到这一点,我实际上并没有真正做到这一点。我甚至无法想象这实际上是必要的情景,但我很想知道它是否可能。

所以我的(完全理论上的,完全不切实际的)问题是:是否可以为命令行参数定义自己的行为?如果是的话,怎么会这样做呢?如果它是相关的,我使用的是Ubuntu 16.04和GNOME终端。

P.S。

我刚刚在写这个问题时意识到,完全有可能(可能是可能的)C脚本完全不知道外面发生了什么,并且终端仿真器正在准备命令行参数C程序。

4 个答案:

答案 0 :(得分:5)

参数的设置实际上并不在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;
}

答案 1 :(得分:0)

操作系统是将参数数量和参数本身从命令行传递给C程序的操作系统。

函数main对其参数并不挑剔。您根本不会参与任何争论,只能获得argc,您可以同时获得argcargv

你甚至可以获得你想要的任何类型的3或4个参数,但它们将包含垃圾。操作系统将始终将参数的数量及其名称作为int和指向字符串的指针数组传递。

答案 2 :(得分:0)

您的code声明实际上并未定义您获得的参数。这是程序环境的责任:操作系统和调用程序,通常是命令行处理器。

调用者(通常是一个shell程序)准备参数并将它们传递给适当的操作系统程序,以便调用程序。操作系统例程通常在堆栈上为被调用者准备这些数据,然后跳转到程序的入口点,然后进入<?php global $wpdb; $items_per_page = 10; $id_post = isset( $_GET['id'] ) ? abs( (int) $_GET['id'] ) : 1; $page = isset( $_GET['cpage'] ) ? abs( (int) $_GET['cpage'] ) : 1; $chapter = isset( $_GET['chapter_no'] ) ? abs( (int) $_GET['chapter_no'] ) : 1; $bookName= isset( $_GET['book'] ) ? urldecode ( $_GET['book'] ) : 1; $offset = ( $page * $items_per_page ) - $items_per_page; $query = "(Select id, hadith_no, content FROM data WHERE book='$bookName' AND chapter_no='$chapter')"; $total_query = "SELECT COUNT(*) FROM (${query}) AS combined_table"; $total = $wpdb->get_var( $total_query ); $latestposts = $wpdb->get_results("Select id, hadith_no, content FROM data WHERE book='$bookName' AND chapter_no='$chapter' LIMIT $items_per_page OFFSET $offset"); foreach ($latestposts as $latestpost) { echo $latestpost->hadith_no." ".str_repeat('&nbsp;', 140)." <a href='http://localhost:8082/tps/permalinks/?id=$latestpost->id'>Permalink</a> ".$latestpost->content."<br>"; $text = $latestpost->content; $words = extractCommonWords($text); echo "Tags: <a>" .implode(' , ', array_keys($words)). "</a>"; echo do_shortcode('[Social9_Share]'); } ?> 函数。

您的main()声明只是声明您的main 期望在堆栈上的内容,它间接定义了如何使用那些数据,但不是它们是什么。这就是为什么你可以在没有参数main()的情况下宣布main的原因 - 这只是意味着无论传递给我什么,我都会忽略它#。 / p>

答案 3 :(得分:0)

有标准(如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;
}