命令行参数计数

5
这是一个简单的C语言程序,可以输出传递给它的命令行参数数量:
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("%d\n", argc);
}

当我输入时
file_name *

在我的电脑(操作系统为Windows 7)上,它打印出623而不是2。但在其他情况下,它会给出正确的输出。 * 是命令行参数的保留字符吗?请注意,对于以下输入,此程序会给出正确的输出:

file_name *Rafi

输出 = 2


@pmg:我已经修改了问题,使得“file_name”成为一个单词而不是两个...这可能是Rafi的本意。如果不是,他会重新编辑,然后我们可以再次对2和3进行怀疑。 - Jonathan Leffler
微软的 C/C++ 编译器(cl.exe)将在您的两个示例中都打印 2。您使用的是不同的编译器吗? - user7116
没错,你说得对 :) @Jonathan - Rafi Kamal
4个回答

10
在Unix命令行上,shell负责处理通配符。 yourapp *将运行yourapp,并将当前目录中所有非隐藏文件的名称作为参数传递。在您的情况下,有622个文件(623 = 622个文件+程序名称)。
在Windows上,应用程序负责通配符解析,因此argc为2,其中1个是程序名称(argv [0]),另一个是通配符(argv [1] = *)。

谢谢 :) 我认为623只是一个错误 :) - Rafi Kamal
@Brian:这不是“错误”,只是不同而已。Windows的样式使得像ren *.jpg *.jpeg这样的事情成为可能,而在Unix系统上这很难做到。 - Marc B
“for f in *.jpg; do mv $f echo $f | cut -d'.' -f1.jpeg; done”除了在文件名中有多个“.”字符时无法正常工作之外,还有什么难点吗?(实际上,这是一个很好的例子,说明了Windows方式也有优势)。 - Brian McFarland
@William:是的,那很方便,但那是一个Perl脚本,不是一个shell命令。只使用shell,for循环是复制Windows在单个命令中所做的事情的唯一实用方法。 - Marc B
@MarcB:在Windows上,REN是一个“命令”,不是吗?因此,在Unix上执行命令只需要将名称包含在引号中:“/usr/bin/ren '.jpg' '.jpeg'”可以编写,并且可以做到人们想要的 - 但我同意这不是Unix的方式™,有时人们会忘记引号并感到困惑和/或混乱(除非“ren”命令被编写为拒绝超过两个用户参数(argc > 3),或当两个参数都没有包括单个“*”元字符时拒绝它)。 - Jonathan Leffler
@Jonathan:ren是内置于cmd.exe/command.com中的,因此虽然它是一个命令,但它并不同于运行一个完整的可执行文件。 - Marc B

3

*会被shell或运行库(*nix上是前者,Windows上是后者)展开,而不是直接使用*,这样你会得到当前工作目录中所有文件的名称。


2
正如其他人所提到的,你遇到了“shell通配符扩展”或“globbing”,其中*被用作通配符来匹配文件名并放置在argv数组中。
在Unix系统上,这是由shell执行的,与C运行时几乎没有关系。
在Windows系统上,除非你使用类似于Cygwin的某些类Unix shell替代品,否则该功能不会由shell执行。根据你使用的工具和/或链接器选项,可能会执行C运行时的初始化以实现globbing功能。
  • if you're using Microsoft's compiler, the C runtime will not perform globbing by default, and you would get an argc value of 2 in your example. However, if you ask the linker to link in setargv.obj (or wsetargv.obj if you have a Unicode build), then globbing is added to the runtime initialization and you'll get behavior similar to Unix's. setargv.obj has been distributed with MSVC for as long as I can remember, but it's still little known. I believe that most Windows programs perform their own wildcard expansion.

  • if you're using the MinGW/GCC tool chain, the C runtime will perform globbing before calling main() (at least it does for MinGW 4.6.1 - I suspect it's been in MinGW for a long time). I think MinGW might not perform globbing for GUI programs. You can disable MinGW's globbing behavior with one of the following:

    1. define a global variable named _CRT_glob and initialize it to 0:

      int _CRT_glob = 0;
      
    2. link in the lib/CRT_noglob.o object file (I think this might be order dependent - you may need to place it before any libraries):

      gcc c:/mingw/lib/CRT_noglob.o main.o -o main.exe
      

关于 setargv.obj 的一条非常棒的信息,非常有帮助,谢谢! - Vladimir Sizikov

1
问题在于shell将*扩展为当前目录中所有文件名(不以.开头)。这与C程序关系很小,主要与shell有关。 argc的值包括程序自身名称的1个参数,以及由shell传递的每个参数的1个参数。
尝试:
filename *
filename '*'

第一个将给你623(多少不一定,但是现在是时候清理一下那个目录了!)。第二个将给你2。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接