前面的内容中,我们写main函数通常是这样的

int main()
{
    //code
    return 0;
}

        但是在嵌入式等领域我们也发现了这样一种写法

int main(int argc char*argv[])
{
    //code
    return 0;
}

        这是什么意思呢?我们来解释一下

        代码已经上传至gitee:楼田莉子/Linux学习 - Gitee.com喜欢请点个赞谢谢

目录

前言测试

深入解释:为什么需要参数?

        命令行参数 - 最常见的用途

        环境变量 - 另一个重要用途

        关注点分离

        程序可配置

        接口标准化

        脚本自动化

现代C++替代方案

总结:从专业角度看待


前言测试

        以以下代码为例

//main_test.c
#include <stdio.h>
int main(int argc ,char *argv[])
{
  printf("程序名称: %s\n", argv[0]);
  printf("参数个数 (包括程序名): %d\n", argc);
  int i=0;
  for (; i < argc; i++) 
  {
    printf("argv[%d]-> %s\n", i, argv[i]);
  }
  return 0;
}

        参数含义:

  • argc参数计数

    • 类型:int

    • 含义:表示命令行参数的数量

    • 重要argc的值至少为1,因为第一个参数总是程序本身的名称

  • argv参数向量

    • 类型:char*数组(字符串数组)

    • 含义:包含所有命令行参数的字符串数组(指针数组)

    • 索引规则

      • argv[0]:程序名称或路径

      • argv[1] 到 argv[argc-1]:用户提供的实际参数

      • argv[argc]:保证为NULL指针

        有两种写法

int main(int argc, char *argv[])   // 最常用
int main(int argc, char **argv)    // 等价形式

        接下来我们在Linux系统下进行编译运行测试,结果如下:

        本质上这种命令

./main_test a b c

        是一个字符串。被shell拿到后以空格为分隔符分割为若干字串。argc是被分出来多少字串,argv是字串头指针。

        以上内容都是由shell完成的。

        同理这样也可以:

        以代码证明

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        printf("命令错误,应该这样:>%s -a|-b|-c \n", argv[0]);
        return 1;
    }
    
    // 修正:移除多余的括号,正确使用strcmp
    if(strcmp(argv[1], "-a") == 0)
    {
        printf("我现在执行的是第一种命令\n");
    }
    else if(strcmp(argv[1], "-b") == 0)
    {
        printf("我现在执行的是第二种命令\n");
    }
    else if(strcmp(argv[1], "-c") == 0)
    {
        printf("我现在执行的是第三种命令\n");
    }
    else
    {
        printf("我现在执行的是默认命令\n");  // 添加了换行符
    }
    
    return 0;
}

        结果为:

        证明了以下内容:

        1: 命令行参数,至少是1,argc >= 1,argv[0] 一定会有元素,指向的就是程序名!

        2:选项,是以空格分隔的字符串,一个字符,也是字符串!

        3: argv指针数组的元素有argc个, argv[argc-1] 是最后一个,argv[argc] == NULL

        以上的内容就像命令好的实现一样

        命令行参数的本质应用,是为了实现一个命令,可以根据不同的选项,实现不同的子功能!
也是Linux中所有命令选项功能的实现方式!!!

深入解释:为什么需要参数?

  main 函数是操作系统和您编写的程序之间的桥梁。当您在命令行(如终端、命令提示符或 PowerShell)中启动一个程序时,操作系统需要一种方式将“外部信息”传递到您的程序内部。main 函数的参数正是为了这个目的而存在的。

        命令行参数 - 最常见的用途

        这是最主要、最常见的原因。它允许用户在启动程序时动态地提供信息,而不是将这些信息硬编码在程序内部。

        为什么这很重要?

  • 灵活性:同一个程序可以根据不同的输入执行不同的操作。例如,cp source.txt dest.txt 中的 cp 命令通过参数知道要复制哪个文件以及复制到哪里。

  • 脚本化和自动化:可以在脚本中调用程序并传递参数,实现自动化流程。

  • 配置:用户无需修改源代码即可改变程序行为(例如,指定日志级别、文件路径等)。

        环境变量 - 另一个重要用途

        在某些系统中(尤其是嵌入式系统或特定运行时),main 函数可能有第三个参数,用于传递环境变量。

int main(int argc, char *argv[], char *envp[]) {
    // envp 是一个包含环境变量的字符串数组,以 NULL 结尾
    for (int i = 0; envp[i] != NULL; i++) {
        printf("环境变量 %d: %s\n", i, envp[i]);
    }
    return 0;
}

        运行结果:

        关注点分离

  1. 问题:如果没有参数,所有配置都必须硬编码在源代码中
  2. 解决方案:参数将"要做什么"(算法)与"对什么做"(数据)分离
  3. 专业价值:符合软件工程的"高内聚、低耦合"原则

        程序可配置

// 硬编码的方式 - 不灵活
process_file("input.txt", "output.txt");

// 使用参数的方式 - 灵活
process_file(argv[1], argv[2]);

        接口标准化

  • 所有C/C++程序都使用相同的参数传递机制

  • 操作系统loader有统一的启动协议

  • 开发者有可预测的行为模式

        脚本自动化

# 可以在shell脚本中批量处理
for file in *.txt; do
    ./myprogram process "$file" "output_$file"
done

现代C++替代方案

#include <vector>
#include <string>

int main(int argc, char* argv[]) 
{
    std::vector<std::string> args(argv, argv + argc);
    // 使用args向量进行安全操作
    return 0;
}

总结:从专业角度看待

        从编程专业的角度来看,为 main 函数提供参数是一种设计上的最佳实践,它实现了以下几个关键原则:

  1. 松耦合:程序逻辑与具体的输入数据解耦。程序的核心算法不关心参数是来自命令行、配置文件还是另一个程序,它只处理通过接口(参数)传入的数据。

  2. 可重用性:一个接受参数的程序比一个将所有数据都写死在代码里的程序具有更高的可重用性。

  3. 符合 Unix 哲学: “一个程序只做一件事,并把它做好”。通过参数,一个简单的程序可以被组合到复杂的管道和脚本中,完成更强大的功能。

  4. 清晰的程序接口: main 函数的参数定义了程序与外部世界(操作系统、用户、其他程序)的契约。任何调用该程序的人都知道如何向其传递信息。

        因此,main 函数有参数是为了实现程序与外部环境(特别是命令行 shell)的交互,从而使程序更加灵活、强大和通用。 这种设计同样体现了专业软件开发中的关键原则:通过清晰的接口实现松耦合,通过标准化实现互操作性

        本期的解释到这里就结束了,喜欢请点个赞谢谢

封面图自取:

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐