重新分配 argv
Posted
技术标签:
【中文标题】重新分配 argv【英文标题】:Reallocation of argv 【发布时间】:2015-11-08 16:45:03 【问题描述】:当我在 main
函数(第 78 行)中看到这段代码时,我正在查看 GNU coreutils 包的代码,特别是 the program 'yes':
if (argc <= optind)
optind = argc;
argv[argc++] = bad_cast ("y");
数组argv
怎么可以这样展开呢?显然,将任何代码 sn-p 脱离上下文是一个非常糟糕的主意,所以我查看了 argv
是否事先被修改过,除了对 initialize_main (&argc, &argv)
的调用之外似乎没有,这似乎不需要为“新大小”或类似的东西争论(但在 C 中,就像任何语言一样,事情并不总是它们看起来的样子)。
我决定写一个简单的程序来测试我是否可以在argv
上调用realloc()
char** new_argv = realloc(argv, ++argc * sizeof*argv);
它有效(在 Windows 10 上使用 VS2013)。它返回一个指向已分配内存的指针。当然,如果它是未定义的行为,那实际上并不意味着 任何东西。
所以,长话短说,我的问题是,argv
是如何分配的?重新分配argv
真的安全吗?
【问题讨论】:
我很确定它是未指定的,因此是 UB;你最好 malloc + memcpy。考虑一下 coreutils 是为特定平台编写的,其中一些行为是已知的。argv
是指向char
(程序拥有)的指针数组,最后一个,即argv[argc]
应该是空指针,所以可以让它指向到别的东西。
【参考方案1】:
argv[argc++] = bad_cast ("y");
这不会扩展argv
数组。它只是为argv[argc]
赋值,然后递增argc
。这确实打破了argv[argc] == NULL
的初始保证,但只要代码不依赖于它是有效的。
标准保证:
参数
argc
和argv
以及argv指向的字符串 数组应可由程序修改,并保留其最后存储的 程序启动和程序终止之间的值。
它没有明确保证argv
指向的数组中的char*
指针是可修改的,但这是一个合理的假设。 (严格来说argv
指向数组的第一个元素,而不是数组本身,但那句话已经够长了。)
char** new_argv = realloc(argv, ++argc * sizeof*argv);
这具有未定义的行为。 realloc
的第一个参数必须是空指针或指向由 malloc
、calloc
、realloc
或等效项分配的内存的指针。 argv
指向的内存在进入main
之前以某种未指定的方式分配。您可以制作数组的副本,但不能合法地释放它,这是realloc
所做的一部分。如果realloc
调用对您来说表现“正确”,那么您就是不走运。 (如果你幸运,你的程序就会崩溃,这会告诉你有问题。)
【讨论】:
我更喜欢这个答案,因为它更深入、更直接地回答了我的问题。 优秀的答案!尤其是UB和倒霉/幸运的部分。【参考方案2】:首先,argv[argc]
被定义为NULL
。
其次,argc++
递增 argc
但返回其旧值。
因此,argv[argc++] = ...
不会调用未定义的行为;它只是为以前的NULL
指针分配一个新值。
【讨论】:
argv[argc]
是否保证为NULL
?
@ThePcLuddite 它是,从标准 5.1.2.2.1 程序启动 - 2 argv[argc] shall be a null pointer.
以上是关于重新分配 argv的主要内容,如果未能解决你的问题,请参考以下文章
当 React 功能组件重新渲染时,它会重新分配分配的值和功能吗?