main 函数的 argv 参数用 char* argv[ ]还是 char** argv 合适?

2019-07-08 10:33:43 +08:00
 shijingshijing

这个问题其实以前没怎么注意,反正都是指向字符串的指针,但是最近看几个底层库的实现,基本上都是用的

int main(int argc, char** argv)

这种形式进行声明

以前没怎么关注过这个细节,写过

int main(int argc, char* argv[])

好像也经常有

int main(void)

甚至

void main(void)

阿里巴巴的 Java 开发手册里面第 7 条也提到了强制使用 String[] args 而否定了 String args[]这种形式。

Visual Studio 新建项目自动生成的代码也是使用了 string[] args。

想了解一下,这个里面究竟有什么讲究?如果是 c 和 c++的话,是不是一定写成 char** argv 更好?

4202 次点击
所在节点    程序员
33 条回复
andrewhxism
2019-07-08 10:41:16 +08:00
语法上的区别,等效于没区别
maxco292
2019-07-08 10:43:28 +08:00
void main 是 c 式语法,不推荐,其他没啥区别
PTLin
2019-07-08 10:50:27 +08:00
UNIX 风格是 int main(int argc, char *argv[])和 int main(void),其实还有一种 int main(int argc, char *argv[], char *envp[]),其中第三个参数是环境表地址,我感觉还是 char *argv[]更符合直觉。
shijingshijing
2019-07-08 10:51:42 +08:00
@maxco292
恩,这个我知道,我忘记在哪本书里看到过了,好像说的是其实 C 还是 UNIX,自始至终都没有强制要求 int 返回值,也没有要求一定要有 argc 和 argv 参数。(具体记不太清楚了)我不是纠结 int main(void)和 void main(void)这两种。

@andrewhxism
我的意思是,为什么阿里要求强制用 String[] args 而否定 String args[],如果刚好项目里面用到了一个第三方提供的源代码库,里面都是 String args[],他们会怎么处理。。。
这个要求只是简单的为了避免引入书写错误而规定的?还是有其他性能或者质量方面的考量?
haozhang
2019-07-08 11:05:08 +08:00
char *argv[]更好,明确表明是 char *数组。
ejq
2019-07-08 11:05:58 +08:00
@shijingshijing String[] 是 Java 风格
gunavy
2019-07-08 11:46:15 +08:00
辛亏你不做 js,要不你的整个人生都是纠结的😂
forcecharlie
2019-07-08 11:59:22 +08:00
其实无所谓,无论哪一种形式的 main 编译后的函数名依然是 main,这是 C Style 的,无论采用什么形式的 main,编译时,链接器会帮你自动将将进程的入口点链接到 main。如果你不需要命令行参数,可以使用 `int main()`,如果你需要修改 命令行参数,可以使用 `int main(int argc,char **argv)`(这通常在 Linux 系统修改 ps 进程名。),否则可以使用 `int main(int argc, char* argv[])`。envp 需要则使用,不需要不使用。

https://github.com/bminor/musl/blob/65c8be380431eebe4d70d130bd38563f8df9a7d7/src/env/__libc_start_main.c

https://github.com/bminor/musl/blob/master/crt/rcrt1.c
ipwx
2019-07-08 12:03:52 +08:00
老哥,C++ 没有 string[] argv 这种用法。

不同语言的代码风格,能参考嘛?
Mithril
2019-07-08 12:07:08 +08:00
看你提到了 VS,大概应该是 Windows 程序了。
Windows 程序的入口其实是个 int (*)(void),没有入口参数的。Windows 创建进程以后调用 PE 入口就没有参数。
然后你的 CRT 会初始化,它会用 GetCommandline 一类的 Windows API 从系统获取 PEB 里面保存的命令行参数,然后构造出一块内存保存这些东西,再用这玩意作为你的 main 函数的参数,调用你的 main。
CRT 传给你的是个 char **,你愿意转成[]随你便的。
包括 Java 那个也是一样,所有写成 main 的东西都是由 Runtime 调用的,Runtime 设计成什么样传进去的参数就是什么样了。
GeruzoniAnsasu
2019-07-08 12:23:32 +08:00
这个现象是这样的
几乎所有的 ide 自动生成 main 函数用的都是 char *argv[]这种形式

但不翻一下文档你一般很难想起来*和[]哪个优先级高,要不要写括号。所以手写开头一般 char**,不会错,也不用考虑括号



破案:你你看到的那些底层库估计是 vim 写的,没有 ide 自动生成 main
vkhsyj
2019-07-08 12:26:16 +08:00
两个是一样的,两个都是通俗写法,个人觉得 char* argv[] 语义更加明确
codehz
2019-07-08 12:53:05 +08:00
@Mithril #10 linux 也是这样(入口点是 crt 的函数,准备好各种参数后然后再调用 main (不然你试试强行改入口点到 main 会不会崩(
Mithril
2019-07-08 13:33:46 +08:00
@codehz 我的意思是 Windows 的 PE 入口是个 int (*)(void),linux 不太清楚是不是。但是 CRT 这些东西都是一致的。
shijingshijing
2019-07-08 15:53:25 +08:00
@ipwx
我说 Visual Studio 明显是说 C#啊,你在 Visual Studio 里面新建 C++工程,VS 自动给你生成的 boilerplate 是这种:
```
int main(array<System::String ^> ^args)
```

我现在其实最想知道的是为什么阿里 Java 开发手册里规定强制使用 String[] args 且否定了 String args[],比较好奇原因。
wdv2ly
2019-07-08 17:30:39 +08:00
好奇,java 有第二种写法吗?反正 c#没有第二种写法
jamesliu96
2019-07-08 17:35:51 +08:00
想开点😶
smdbh
2019-07-08 18:01:58 +08:00
面向 memory 编程,就不纠结了
geelaw
2019-07-08 18:40:38 +08:00
楼主问了好几个不同的问题。

就 C/C++ 标准来说,正确的 main 的签名只有以下 2 种

int main(void);
int main(int, char **);

注意,char *argv[] 和 char **argv 作为形参是完全一样的,以及使用 typedef 导致的等价定义也是允许的。就语言层面,没有什么讲究。

就 Java 来说,一维数组形参可以用 TypeName argName[] 或者 TypeName[] argName 声明,它们是等价的写法。阿里巴巴的规范是选择他们内部喜欢的写法,原因可以理解为把类型名挤在一起便于理解。

C# 中,一维数组的形参可以用 TypeName[] argName 声明,不能使用 TypeName argName[] 的原因是后者是 C# 中不存在的写法(不符合句法)。
ipwx
2019-07-08 19:00:56 +08:00
@shijingshijing 首先,Java 不存在指针。C# safe 代码不存在指针。所以你的出发点就不一样。

其次,<System::String^> 不是 C++ 项目,是 .NET C++ 项目,两者截然不同。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/580911

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX