English 中文(简体)
argv [n] 是否值得?
原标题:Is argv[n] writable?

C11.2.2.1/2说:

The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

My interpretation of this is that it specifies:

int main(int argc, char **argv)
{
    if ( argv[0][0] )
        argv[0][0] =  x ;   // OK

    char *q;
    argv = &q;              // OK
}

但它没有说什么:

int main(int argc, char **argv)
{
    char buf[20];
    argv[0] = buf;
}

是否允许<代码>argv[0] = buf;?

我至少可以看到两个可能的论点:

  • The above quote deliberately mentioned argv and argv[x][y] but not argv[x], so the intent was that it is not modifiable
  • argv is a pointer to non-const objects, so by in the absence of specific wording to the contrary, we should assume they are modifiable objects.
问题回答

IMO, code like argv[1] = "123"; is UB (using the original argv).


“参数<代码>argc和argv及<编码>指明的参数> 阵列应按照方案加以修改,保留方案启动与方案终止之间的最后储存价值。 C11dr & C17dr 1 §5.1.2.2.1 2

请注意,<条码>const在C s创建多年后进入C。

远如<代码>char*s = “abc”; 有效时应为const char *s = “abc”;。 不需要<代码>const,否则,如果采用const,就会有太多的现有代码被打破。

同样,即使今天的<代码>argv仍应视为 const argv[ ]或与const的其他签字,但constchar *argv[] 上并未完全指明const>const>/code>-ness needs of the argv,, 或, 或< <代码>const-ness needs to bezan by the spec.

从我的理解来看,由于光谱对该问题保持沉默,但对于<代码>main(>>argv = argv[i][j] =的其他转让,该词为UB。

本国际报告中另有未界定的行为说明。 标准为“不明确的行为”或 放弃行为的任何明确定义 第2条


[编辑]:

<代码>main()是C的一个非常特殊的职能。 在其他职能中可以允许的,可在<代码>main()上允许。 C 光谱详细描述给出签名的参数:int argc, char *argv[],即线性需要。 <代码>main(,与C中的其他职能不同,可有替代签名int main(避开)及潜在的其他功能。 <代码>main(>不适用。 由于C spec偏离了详细阐明可以修改的内容:argc,argv,argv[][,有理由怀疑argv[]是否因该代码的推测而不可更改。

鉴于<代码>main()的特殊性以及未指明argv[>为可更改性的情况,一位保守的方案主管将在未来的Cspec澄清之前将这种灰色作为UB处理。


如果argv[i]在某一特定平台上可以更改,那么i的范围当然不应超过argc-1

As "argv[argc] shall be a null pointer", assignining argv[argc] to something other than NULL appears to be a violation.

虽然这些指示是可更改的,但代码不应超过原封状的长度。

char *newstr = "abc";
if (strlen(newstr) <= strlen(argv[1])) 
  strcpy(argv[1], newstr);

1 No change with C17/18. Since that version was meant to clarify many things, it re-enforces this spec is adequate and not missing an "argv array elements shall be modifiable".

The argv array is not required to be modifiable (but may be in actual implementations). This is an intentional wording which was reaffirmed in the n849 meeting in 1998:

rel=“noreferer”> https://www. open-std.org/jtc1/sc22/wg14/www/docs/n849.htm

PUBLIC REVIEW COMMENT #7

[...]

Comment 10.
Category: Request for information/clarification
Committee Draft subsection: 5.1.2.2.1
Title: argc/argv modifiability, part 2
Detailed description:

Is the array of pointers to char pointed to by argv modifiable?

Response Code: Q
    This is currently implictly unspecified and the committee 
    has chosen to leave it that way.

In addition, two separate proposals were made to, respectively, change and augment the wording. Both were rejected. Interested readers can find them by searching for "argv".


Trivia: an example in the Kernighan and Ritchie The C Programming Language, 2nd ed, ("K&R2") runs afoul of this. It is on page 117, and the relevant line of code is:

while (c = *++argv[0])

那些在争论中添加点的人本身是为了通过扼杀的性质而向前迈进。

这一措辞和限制对<代码>argv的改动的可能理由之一 阵列本身是允许使用<代码>argv的阵列及其所含的Cstrings Smalloc,并在从main/code>返回后予以释放。 指称:

    // C startup
    [...]
    // allocate the command line argument array
    int argc = os_get_argument_count();
    char **argv = malloc(sizeof *argv * (argc + 1));
    for (int i = 0; i < argc; i++)
        argv[i] = strdup(os_get_argument(i));
    argv[argc] = NULL;
    [...]
    // calling main
    int status = main(argc, argv, envp);
    // call atexit functions, etc.
    [...]
    // release arguments
    for (i = 0; i < argc; i++)
        free(argv[i]);
    free(argv);
    os_exit_with_status(status);

如果对<代码>argv阵列进行修改,上述假设性图书馆代码将不明确。

这是一种理论上的例子,在实践中,没有理由在要求<代码> 主要后注意<代码>argv阵列内容,而实际上无法汇编和操作许多C方案,修改<代码>argv,供辩论用。

<代码>argc仅为int<>/code>,可不受限制地更改。

www.un.org/chinese/ga 这意味着<代码>argv[i] = x有效。 但它没有说什么东西可以更改<代码>argv[i]。 因此,<代码>argv[i][j] = c导致不明确的行为。

C标准图书馆的<代码>getopt/code>功能确实修改了增益和增减,但从未修改过实际的果园。

答案是,振奋剂是一种阵容,但其内容是不可调和的。

该关键部分较早:

If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup.

从这一点来看,显然要把“财富”视为一系列具体的时间(ar)。 其后,*argv是该阵列的指点,被降为点子。

在此情况下,关于“Argv”应具有可变性的声明......并保留其内容,显然意在改变该阵列的内容。

我承认,措辞仍有一些含糊不清之处,特别是如果修改动力,可能会发生什么。


简言之,我说的是,我把这一措辞理解为:

[......]增量[记录]和增量阵列指出的示意图应具有可变性......

因此,阵列中的指点和它们所显示的星号都记忆中,不会通过改变阵列来造成伤害,而且两者都保持了方案生命的价值。 我预计,这一行为将毫无例外地出现在所有C/C++主要运行时间的图书馆执行中。 这不是联邦。

含糊不清之处是提到了一种动力。 难以想象的是,任何目的或任何执行都无法改变(这似乎只是地方功能参数)的增量价值,为什么会提到这一点? 该标准明确指出,一项职能可以改变其参数的价值,因此,如何在这方面特别对待增益? 正是这种意想不到的提及激发了人们对活力的担忧,否则会毫无保留地通过。 删除句子的引力,模糊之处消失。

It is modifiable, and gdb with -std=11 shows what happens

国际标准化组织C11,2011年国际标准化组织C标准的修订。 这一标准得到了完全的支持。 因此,让我们安全地假设,电梯汇编者支持C11标准文件提出的大多数特征。 选择——C11标准将编制方案。

argv[] is just array of string pointers like arguments of any other function they are treated as local variables and are modifiable. Since they belong to main() function they will last until program exits..

<代码>char **argv (pointer to pointer)和int argc均为main( function,从而在一栏中形成。

If we run this code and stop at breakpoint at main(): :~/proba$ gdb --args proba BBBBBBB CCCCCCC

#include <stdio.h>
    
int main(int argc, char **argv)
{
    char buf[20] = "AAAAAAA";
    argv[0] = buf;
    return 1;
}

Starting program: /home/drazen/proba/proba BBBBBBB CCCCCCC
Breakpoint 1, main (argc=3, argv=0x7fffffffdef8) at main9.c:5

如果我们 dump倒,我们看到:

(gdb) x/32gx $sp
0x7fffffffddb0: 0x00007fffffffdef8  0x0000000300000000
0x7fffffffddc0: 0x0000000000000000  0x0000000000000000
0x7fffffffddd0: 0x0000000000000000  0x0000000000000000
.......

We recognize value of argv 0x00007fffffffdef8 and value of argc 0x00000003 on top of a stack.

由于我们通过了一个论点<代码>argc,按预期为3。

But argv holds address of the array of char pointers. So at address 0x00007fffffffdef8 is actually address of the first pointer argv[0] with value 0x00007fffffffe25c, what should be an address where program name with absolute path is.

And at address 0x7fffffffdf00 is second pointer argv[1] with value 0x00007fffffffe275 what should be an address where first program argument is. And at address 0x7fffffffdf08 is third pointer argv[2] with value 0x00007fffffffe27d what should be an address where second program argument is.

我们可以看到:

........
0x7fffffffdef0: 0x0000000000000003            0x00007fffffffe25c<argv[0]>
0x7fffffffdf00: 0x00007fffffffe275<argv[1]>   0x00007fffffffe27d<argv[2]>

http://code>argv[0] 。

(gdb) x/s 0x00007fffffffe25c
0x7fffffffe264: "/home/drazen/proba/proba"

地址:0x00007fffe275 。 BBBBBBB:

(gdb) x/s 0x00007fffffffe275
0x7fffffffe27d: "BBBBBBB"

And at address 0x00007fffffffe27d is third argument argv[2] which holds address of a program argument CCCCCCC:

(gdb) x/s 0x00007fffffffe27d
0x7fffffffe27d: "CCCCCCC"

我们看到,标明这些字面的字面编号为<>char*argv[]点数,以连续地址标示:

(gdb) x/3s 0x00007fffffffe25c
0x7fffffffe25c: "/home/drazen/proba/proba"
0x7fffffffe275: "BBBBBBB"
0x7fffffffe27d: "CCCCCCC"

Now let s step few instructions where we initialize local string variable on stack and reassign pointerargv[0]:

(gdb) s
6       char buf[20] = "AAAAAAA";
(gdb) s
7       argv[0] = buf;
(gdb) s
8       return 1;

If we dump the stack now we notice it has slightly changed. We see that local variable buf[] was initialized on stack too (string AAAAAAA is HEX 0x0041414141414141) right after main() function arguments:

(gdb) x/32gx $sp
0x7fffffffddb0: 0x00007fffffffdef8  0x0000000300000000
0x7fffffffddc0: 0x0041414141414141  0x0000000000000000
0x7fffffffddd0: 0x0000000000000000  0x5315d27018aa8e00
.....
.....
0x7fffffffdef0: 0x0000000000000003  0x00007fffffffddc0<argv[0]>
0x7fffffffdf00: 0x00007fffffffe275  0x00007fffffffe27d

Value 0x00007fffffffdef8 of argv hasn t changed, but value of argv[0] has changed to 0x00007fffffffddc0:

.....
0x7fffffffdef0: 0x0000000000000003  0x00007fffffffddc0<argv[0]>
0x7fffffffdf00: 0x00007fffffffe275  0x00007fffffffe27d


(gdb) x/s 0x00007fffffffddc0
0x7fffffffddc0: "AAAAAAA"
(gdb) p argv[0]
$1 = 0x7fffffffddc0 "AAAAAAA"

pointer argv[0] now points to the new memory location where string literal "AAAAAAA" is allocated on a stack.





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签