解析 C 中的命令行参数

2023-12-29

我正在尝试编写一个程序,可以在 C 中逐行、逐字或逐字符地比较两个文件。它必须能够读取命令行选项-l, -w, -i or --...

  • 如果选项是-l,它逐行比较文件。
  • 如果选项是-w,它逐字比较文件。
  • 如果选项是--,它会自动假定下一个参数是第一个文件名。
  • 如果选项是-i,它以不区分大小写的方式比较它们。
  • 默认情况下逐个字符地比较文件。

输入选项多少次并不重要,只要-w and -l不是同时输入的,并且文件数量不得超过或少于两个。

我什至不知道从哪里开始解析命令行参数。

这就是我为所有事情想出的代码。我还没有进行错误检查,但是我写的东西是否过于复杂了?

/*
 * Functions to compare files.
 */
int compare_line();
int compare_word();
int compare_char();
int case_insens();

/*
 * Program to compare the information in two files and print message saying
 * whether or not this was successful.
 */
int main(int argc, char* argv[])
{
    /* Loop counter */
    size_t i = 0;

    /* Variables for functions */
    int caseIns = 0;
    int line = 0;
    int word = 0;

    /* File pointers */
    FILE *fp1, *fp2;

    /*
     * Read through command-line arguments for options.
     */
    for (i = 1; i < argc; i++)
    {
        printf("argv[%u] = %s\n", i, argv[i]);
        if (argv[i][0] == '-')
        {
             if (argv[i][1] == 'i')
             {
                 caseIns = 1;
             }
             if (argv[i][1] == 'l')
             {
                 line = 1;
             }
             if (argv[i][1] == 'w')
             {
                 word = 1;
             }
             if (argv[i][1] == '-')
             {
                 fp1 = argv[i][2];
                 fp2 = argv[i][3];
             }
             else
             {
                 printf("Invalid option.");
                 return 2;
             }
        }
        else
        {
           fp1(argv[i]);
           fp2(argv[i][1]);
        }
    }

    /*
     * Check that files can be opened.
     */
    if(((fp1 = fopen(fp1, "rb")) ==  NULL) || ((fp2 = fopen(fp2, "rb")) == NULL))
    {
        perror("fopen()");
        return 3;
    }
    else
    {
        if (caseIns == 1)
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(case_insens(fp1, fp2)) == 0)
                        return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(case_insens(fp1, fp2)) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(case_insens(fp1,fp2)) == 0)
                    return 0;
            }
        }
        else
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(fp1, fp2) == 0)
                    return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(fp1, fp2) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(fp1, fp2) == 0)
                    return 0;
            }
        }
    }
    return 1;

    if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL)))
    {
        perror("fclose()");
        return 3;
    }
    else
    {
        fp1 = fclose(fp1);
        fp2 = fclose(fp2);
    }
}

/*
 * Function to compare two files line-by-line.
 */
int compare_line(FILE *fp1, FILE *fp2)
{
    /* Buffer variables to store the lines in the file */
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    /* Check that neither is the end of file */
    while((!feof(fp1)) && (!feof(fp2)))
    {
        /* Go through files line by line */
        fgets(buff1, LINESIZE, fp1);
        fgets(buff2, LINESIZE, fp2);
    }

    /* Compare files line by line */
    if(strcmp(buff1, buff2) == 0)
    {
        printf("Files are equal.\n");
        return 0;
    }
    printf("Files are not equal.\n");
    return 1;
}

/*
 * Function to compare two files word-by-word.
 */
int compare_word(FILE *fp1, FILE *fp2)
{
    /* File pointers */
    FILE *fp1, *fp2;

    /* Arrays to store words */
    char fp1words[LINESIZE];
    char fp2words[LINESIZE];

    if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL)
    {
        printf("File is empty. Cannot compare.\n");
        return 0;
    }
    else
    {
        fp1words = strtok(fp1, " ");
        fp2words = strtok(fp2, " ");

        if(fp1words == fp2words)
        {
            fputs(fp1words);
            fputs(fp2words);
            printf("Files are equal.\n");
            return 0;
        }
    }
    return 1;
}

/*
 * Function to compare two files character by character.
 */
int compare_char(FILE *fp1,FILE *fp2)
{
    /* Variables to store the characters from both files */
    int c;
    int d;

    /* Buffer variables to store chars */
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF)))
    {
        if(c == d)
        {
            if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2)))
            {
                printf("Files have equivalent characters.\n");
                return 1;
                break;
            }
        }

    }
    return 0;
}

/*
 * Function to compare two files in a case-insensitive manner.
 */
int case_insens(FILE *fp1, FILE *fp2, size_t n)
{
    /* Pointers for files. */
    FILE *fp1, *fp2;

    /* Variable to go through files. */
    size_t i = 0;

    /* Arrays to store file information. */
    char fp1store[LINESIZE];
    char fp2store[LINESIZE];

    while(!feof(fp1) && !feof(fp2))
    {
        for(i = 0; i < n; i++)
        {
            fscanf(fp1, "%s", fp1store);
            fscanf(fp2, "%s", fp2store);

            fp1store = tolower(fp1store);
            fp2store = tolower(fp2store);

            return 1;
        }
    }
    return 0;
}

据我所知,在 C 中解析命令行参数的三种最流行的方法是:

  • Getopt (#include <unistd.h>来自 POSIX C 库),可以解决简单的参数解析任务。如果您对 bash 有点熟悉,那么 bash 的内置 getopt 基于 GNU libc 中的 Getopt。
  • Argp (#include <argp.h> from the GNU C Library), which can solve more complex tasks and takes care of stuff like, for example:
    • -?, --help for 帮助信息, 包括电子邮件地址
    • -V, --version for 版本信息
    • --usage for 使用信息
  • 自己做,我不建议将其用于将提供给其他人的程序,因为有太多可能会出错或质量较低的程序。忘记使用“--”来停止选项解析的常见错误只是一个例子。

GNU C 库文档有一些关于 Getopt 和 Argp 的很好的示例。

  • http://www.gnu.org/software/libc/manual/html_node/Getopt.html http://www.gnu.org/software/libc/manual/html_node/Getopt.html
  • http://www.gnu.org/software/libc/manual/html_node/Argp.html http://www.gnu.org/software/libc/manual/html_node/Argp.html

使用示例Getopt

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

int main(int argc, char *argv[])
{
    bool isCaseInsensitive = false;
    int opt;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;

    while ((opt = getopt(argc, argv, "ilw")) != -1) {
        switch (opt) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument.
    // If it is >= argc, there were no non-option arguments.

    // ...
}

使用示例Argp

#include <argp.h>
#include <stdbool.h>

const char *argp_program_version = "programname programversion";
const char *argp_program_bug_address = "<[email protected] /cdn-cgi/l/email-protection>";
static char doc[] = "Your program description.";
static char args_doc[] = "[FILENAME]...";
static struct argp_option options[] = { 
    { "line", 'l', 0, 0, "Compare lines instead of characters."},
    { "word", 'w', 0, 0, "Compare words instead of characters."},
    { "nocase", 'i', 0, 0, "Compare case insensitive instead of case sensitive."},
    { 0 } 
};

struct arguments {
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode;
    bool isCaseInsensitive;
};

static error_t parse_opt(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;
    switch (key) {
    case 'l': arguments->mode = LINE_MODE; break;
    case 'w': arguments->mode = WORD_MODE; break;
    case 'i': arguments->isCaseInsensitive = true; break;
    case ARGP_KEY_ARG: return 0;
    default: return ARGP_ERR_UNKNOWN;
    }   
    return 0;
}

static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 };

int main(int argc, char *argv[])
{
    struct arguments arguments;

    arguments.mode = CHARACTER_MODE;
    arguments.isCaseInsensitive = false;

    argp_parse(&argp, argc, argv, 0, 0, &arguments);

    // ...
}

示例自己做

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
    bool isCaseInsensitive = false;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
    size_t optind;
    for (optind = 1; optind < argc && argv[optind][0] == '-'; optind++) {
        switch (argv[optind][1]) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }   
    }
    argv += optind;

    // *argv points to the remaining non-option arguments.
    // If *argv is NULL, there were no non-option arguments.

    // ...
}   

免责声明:我是 Argp 新手,该示例可能包含错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解析 C 中的命令行参数 的相关文章

  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • 在搜索 List 时,为什么 Enumerable.Any(Func predicate) 比带有 if 语句的 foreach 慢

    最近有件事引起了我的好奇心 Why is the Enumerable Any Func
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 如何创建可以像 UserControl 一样编辑的 TabPage 子类?

    我想创建一个包含一些控件的 TabPage 子类 并且我想通过设计器来控制这些控件的布局和属性 但是 如果我在设计器中打开子类 我将无法像在 UserControl 上那样定位它们 我不想创建一个带有 UserControl 实例的 Tab
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • 构造函数中显式关键字的使用

    我试图了解 C 中显式关键字的用法 并查看了这个问题C 中的explicit关键字是什么意思 https stackoverflow com questions 121162 但是 那里列出的示例 实际上是前两个答案 对于用法并不是很清楚
  • POCO HTTPSClientSession 发送请求时遇到问题 - 证书验证失败

    我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序 出于测试目的 我正在连接到具有自签名证书的服务器 并且我希望允许客户端进行连接 为了允许这种情况发生 我尝试安装InvalidCertificateHandler这是
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 通过 NHibernate 进行查询,无需 N+1 - 包含示例

    我有一个 N 1 问题 我不知道如何解决它 可以在这个问题的底部找到完全可重复的样本 因此 如果您愿意 请创建数据库 设置 NUnit 测试和所有附带的类 并尝试在本地消除 N 1 这是我遇到的真实问题的匿名版本 众所周知 这段代码对于帮助
  • 当模板类不包含可用的成员函数时,如何在编译时验证模板参数?

    我有以下模板struct template
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 结构体指针的动态数组

    我必须使用以下代码块来完成学校作业 严格不进行任何修改 typedef struct char firstName char lastName int id float mark pStudentRecord pStudentRecord
  • 运算符“==”不能应用于“int”和“string”类型的操作数

    我正在编写一个程序 我想到了一个数字 然后计算机猜测了它 我一边尝试一边测试它 但我不断收到不应该出现的错误 错误是主题标题 我使用 Int Parse 来转换我的字符串 但我不知道为什么会收到错误 我知道它说 不能与整数一起使用 但我在网
  • WinRT 定时注销

    我正在开发一个 WinRT 应用程序 要求之一是应用程序应具有 定时注销 功能 这意味着在任何屏幕上 如果应用程序空闲了 10 分钟 应用程序应该注销并导航回主屏幕 显然 执行此操作的强力方法是在每个页面的每个网格上连接指针按下事件 并在触
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项
  • 错误:无效使用不完整类型“类 Move”/未定义对 Move::NONE 的引用

    拜托 我不知道为什么这个简单的代码被拒绝 它给了我 2 个编译错误 请帮帮我 I use 代码 块 20 03 我的编译器是GNU GCC 移动 hpp class Move public Move Move int int public

随机推荐

  • 我是否需要内存屏障来访问已完成的线程修改的内存?

    以下为 C 术语 我有一个线程 A 和线程 B 共享对整数值 P 的访问 线程 A 初始化该值并在运行时更新它 然后线程A完成 线程 B 等待线程 A 完成 标准操作系统 API 调用 无论使用什么操作系统 并想要读取 P 线程 B 是否需
  • MySQL 更新并从另一个表中选择

    我有3张桌子 Kommuner 和 Fylker 公司 公司表有一个空字段forretningsadresse fylke但另一个领域forretningsadresse kommune有一个值 所以基本上 我需要填写forretnings
  • 表与两个相关表的总和

    我在这里提出这个 我确信是 简单的问题 我不知道如何解决 我有这个架构 有了这个数据 我的预期结果是 对于 约翰 纳什 PERSON NAME TOTAL FRUIT TOTAL COOKIE JOHN NASH 10 38 对于 奥斯卡
  • 包装一个对象

    我有一个对象 它有一堆公共属性 没有 getter 和 setter 坏的 因此 我创建了一个包含属性的类 并为它们创建了 getter 和 setter 我的计划是将对象包装在我的类中 因此这意味着不能直接访问属性 我有点不确定该怎么做
  • 如何在 Web Api 操作中锁定长异步调用?

    我有这样的场景 我有一个 WebApi 和一个端点 触发时会执行大量工作 大约 2 5 分钟 这是一个具有副作用的 POST 端点 我想限制执行 以便如果向此端点发送 2 个请求 不应该发生 但安全总比遗憾更好 其中一个请求将必须等待以避免
  • Android手机与穿戴模块之间共享文件

    几个月前 我最初只使用移动模块开始我的项目 现在我也有兴趣为可穿戴设备配置我的应用程序 也就是说 我的所有文件 Java XML drawables 等 都在移动模块中 所以我是否需要将我想要在移动模块和可穿戴模块之间共享的所有文件传输到新
  • 如何获取 Tensorflow seq2seq 嵌入输出

    我正在尝试使用张量流训练序列到序列模型 并一直在查看他们的示例代码 我希望能够访问编码器创建的向量嵌入 因为它们似乎具有一些有趣的属性 然而 我真的不清楚这是怎么回事 在单词的向量表示示例中 他们详细讨论了这些嵌入的用途 但似乎没有提供访问
  • 如何在开发机器上使用ansible模板本地创建文件

    我从 ansible 开始 正在寻找一种方法来使用 ansible 剧本在服务器和本地环境上创建样板项目 我想在本地使用 ansible 模板来创建一些通用文件 但是我如何使用ansible在本地执行某些操作呢 我读了一些 local ac
  • SSRS 报告每个参数值的重复表

    大家对这里的一般性问题感到抱歉 但我一直在互联网上查找 但找不到解决方案 我有一份 SSRS 报告 在运行之前用户必须输入一个参数 Location 在查询中 指定仅返回该位置匹配的结果 IE where Company location
  • 在reactjs中切换下拉菜单

    我的导航栏上有一个简单的下拉菜单的以下代码 https jsfiddle net jL3yyk98 10 https jsfiddle net jL3yyk98 10 索引 html div div 导航菜单 js var NavMenu
  • Polymer:在纸张按钮按“确定”后获取纸张对话框内的纸张输入值

    我需要在按下 确定 纸张按钮后获取纸张对话框内某些纸张输入字段的值 I have
  • 检查时间是否在某一分钟内的最佳方法是什么?

    我想编写一个简单的 python 脚本 它将检查是否是给定小时 分钟之前的 2 分钟 然后每天或在给定时间的给定日期调用我的函数 该脚本将在 cronjob 中每分钟运行一次 所以执行myfunction 的两种情况 每天 10 55201
  • 如何更改 Tkinter 按钮周围框的颜色?

    我尝试了在 Stackoverflow 上找到的一些东西 例如在按钮周围放置一个框架并为其指定颜色 就像所说的那样here https stackoverflow com questions 53101307 how do i change
  • 两个不常见的PHP运算符一起使用来获取图像像素颜色,请解释

    The PHP 图像颜色 http www php net manual en function imagecolorat php函数可用于获取图像像素的 RGB 值 如文档中所示 im imagecreatefrompng php png
  • 在连接中广播左表

    这是我的加入 df df small join df big id leftanti 它似乎我只能广播正确的数据帧 https stackoverflow com questions 62735494 broadcast join in s
  • 如何使用 Zebra P4t 打印机打印带有尖音符(如“é”)的法语字符

    我的问题是关于用尖音符打印法语字符 例如 etc with a 斑马 P4t 打印机 考虑下面的 ZPL 指令 XA FO20 20 CI28 A0 20 20 FD Amiti FS XZ 我已将这些指令放入编码为 UTF 8 的文件中
  • 使用 Enum.Parse() 时出现意外结果

    class Program static void Main string args String value Two Type enumType typeof Numbers Numbers number Numbers Enum Par
  • Apache Spark 消息理解

    请求帮助来理解此消息 INFO spark MapOutputTrackerMaster Size of output statuses for shuffle 2 is 2202921 bytes 2202921在这里是什么意思 我的工作
  • 声明通用变量类型

    我正在尝试在 C 中声明通用变量类型 我不能使用 C 并且我想到了以下选项 Option1 typedef struct void value ElementType e type Data t Option 2 typedef struc
  • 解析 C 中的命令行参数

    我正在尝试编写一个程序 可以在 C 中逐行 逐字或逐字符地比较两个文件 它必须能够读取命令行选项 l w i or 如果选项是 l 它逐行比较文件 如果选项是 w 它逐字比较文件 如果选项是 它会自动假定下一个参数是第一个文件名 如果选项是