简体   繁体   English

(* ++ argv)[0]和while(c = * ++ argv [0])之间的区别

[英]Difference between (*++argv)[0] and while(c = *++argv[0])

I have the following snippet of code: 我有以下代码片段:

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

     char line[MAXLINE];
     long lineno = 0;
     int c, except = 0, number = 0, found = 0;

     while(--argc > 0 && (*++argv)[0] == '-') //These two lines
        while(c = *++argv[0])                 //These two lines
          switch(c) {
             case 'x':
                  except = 1;
                  break;
             case 'n':
                  number = 1;
                  break;
             default:
                  printf("find: illegal option %c\n", c);
                  argc = 0;
                  found = -1;
                  break;
          }

     ...
}

Containing the following expressions: 包含以下表达式:

while(--argc > 0 && (*++argv)[0] == '-')

Does this expression in the parentheses (*++argv)[0] differ from while(c = *++argv[0]) without parentheses? 括号(*++argv)[0]中的此表达式与不带括号的while(c = *++argv[0])有区别吗?

If so, how? 如果是这样,怎么办? Does (*++argv) mean pointer to the next argument, and does *++argv[0] mean pointer to the next character in the current char array which is being pointed to? (*++argv)是否表示指向下一个参数的指针, *++argv[0]表示指向所指向的当前char数组中下一个字符的指针?

First, K&R have an errata on this particular snippet: 首先,K&R在此特定代码段上有勘误表:

117(§5.10): In the find example, the program increments argv[0] . 117(§5.10):在查找示例中,程序将argv[0]递增。 This is not specifically forbidden, but not specifically allowed either. 这不是明确禁止的,但也没有明确允许。

Now for the explanation. 现在进行解释。

Let's say your program is named prog , and you execute it with: prog -ab -c Hello World . 假设您的程序名为prog ,并使用以下命令执行它: prog -ab -c Hello World You want to be able to parse the arguments to say that options a , b and c were specified, and Hello and World are the non-option arguments. 您希望能够解析参数以说指定了选项abc ,而HelloWorld是非选项参数。

argv is of type char ** —remember that an array parameter in a function is the same as a pointer. argv类型为char **记住,函数中的数组参数与指针相同。 At program invocation, things look like this: 在程序调用时,情况如下:

                 +---+         +---+---+---+---+---+
 argv ---------->| 0 |-------->| p | r | o | g | 0 |
                 +---+         +---+---+---+---+---+
                 | 1 |-------->| - | a | b | 0 |
                 +---+         +---+---+---+---+
                 | 2 |-------->| - | c | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 3 |-------->| H | e | l | l | o | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 4 |-------->| W | o | r | l | d | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 5 |-------->NULL
                 +---+

Here, argc is 5, and argv[argc] is NULL . 在这里, argc为5,而argv[argc]NULL At the beginning, argv[0] is a char * containing the string "prog" . 在开头, argv[0]是一个char *包含字符串"prog"

In (*++argv)[0] , because of the parentheses, argv is incremented first, and then dereferenced. (*++argv)[0] ,由于括号的原因, argv首先递增,然后取消引用。 The effect of the increment is to move that argv ----------> arrow "one block down", to point to the 1 . 增量的作用是将argv ---------->箭头“向下移动一格”,指向1 The effect of dereferencing is to get a pointer to the first commandline argument, -ab . 解引用的作用是获得指向第一个命令行参数-ab的指针。 Finally, we take the first character ( [0] in (*++argv)[0] ) of this string, and test it to see if it is '-' , because that denotes the start of an option. 最后,我们取(第一个字符[0](*++argv)[0]此字符串的,并对其进行测试,看它是否是'-' ,因为这表示选项的开始。

For the second construct, we actually want to walk down the string pointed to by the current argv[0] pointer. 对于第二种构造,我们实际上想遍历当前argv[0]指针所指向的字符串。 So, we need to treat argv[0] as a pointer, ignore its first character (that is '-' as we just tested), and look at the other characters: 因此,我们需要将argv[0]视为指针,忽略其第一个字符(如我们刚刚测试的'-' ),然后查看其他字符:

++(argv[0]) will increment argv[0] , to get a pointer to the first non- - character, and dereferencing it will give us the value of that character. ++(argv[0])将使argv[0]递增,以获得指向第一个非-字符的指针,对其取消引用将为我们提供该字符的值。 So we get *++(argv[0]) . 这样我们得到*++(argv[0]) But since in C, [] binds more tightly than ++ , we can actually get rid of the parentheses and get our expression as *++argv[0] . 但是,由于在C中, []++绑定更紧密,因此我们实际上可以摆脱括号,并将表达式表示为*++argv[0] We want to continue processing this character until it's 0 (the last character box in each of the rows in the above picture). 我们要继续处理此字符,直到它为0 (上图中每行的最后一个字符框)为止。

The expression 表达方式

c = *++argv[0]

assigns to c the value of the current option, and has the value c . c分配当前选项的值 ,并且值为c while(c) is a shorthand for while(c != 0) , so the while(c = *++argv[0]) line is basically assigning the value of the current option to c and testing it to see if we have reached the end of the current command-line argument. while(c)while(c != 0)的简写,因此while(c = *++argv[0])行基本上是将当前选项的值分配给c并对其进行测试以查看是否有到达当前命令行参数的末尾。

At the end of this loop, argv will point to the first non-option argument: 在此循环结束时,argv将指向第一个非选项参数:

                 +---+         +---+---+---+---+---+
                 | 0 |-------->| p | r | o | g | 0 |
                 +---+         +---+---+---+---+---+
                 | 1 |-------->| - | a | b | 0 |
                 +---+         +---+---+---+---+
                 | 2 |-------->| - | c | 0 |
                 +---+         +---+---+---+---+---+---+
 argv ---------->| 3 |-------->| H | e | l | l | o | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 4 |-------->| W | o | r | l | d | 0 |
                 +---+         +---+---+---+---+---+---+
                 | 5 |-------->NULL
                 +---+

Does this help? 这有帮助吗?

yes, you are correct. 是的,你是对的。

while(--argc > 0 && (*++argv)[0] == '-')

is scanning the array (of length argc) of command line arguments one by one looking for those starting with a - option prefix. 正在扫描(长度的argc的)命令行参数逐一阵列寻找那些开始与-选项前缀。 For each of those: 对于每个:

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

is scanning through the set of switch characters that follow the first - in the current argument (ie t and n in -tn , until it hits the string null terminator \\0 , which terminates the while loop, since it evaluates as false. 正在扫描当前参数中第一个-后面的开关字符集(即-tn tn ),直到它到达字符串null终止符\\0为止,该字符串终止while循环,因为它的值为false。

This design allows both 这种设计允许

myApp -t -n

and

myApp -tn

to both work and be understood as having the options t and n . 既起作用又被理解为具有选项tn

Incrementing argv is a very bad idea, as once you have done so it is difficult to get the original value back. 递增argv是一个非常糟糕的主意,因为一旦完成,就很难找回原始值。 It is simpler, clearer and better to use an integer index - after all argv IS an array! 使用整数索引更简单,更清晰,更好-毕竟argv是一个数组!

To answer your question ++argv increments the pointer. 要回答您的问题,++ argv会增加指针。 This then has indirection applied to it to get the first character. 然后对它应用了间接获取第一个字符。

The parentheses change the order in which the expressions are evaluated. 括号会更改表达式的计算顺序。

Without parentheses *++argv[0] : 没有括号*++argv[0]

  1. argv[0] gets the pointer to character data currently pointed to by argv . argv[0]获取指向argv当前指向的字符数据的指针。
  2. ++ increments that pointer to the next character in the character array. ++将该指针增加到字符数组中的下一个字符。
  3. * gets the character. *获取角色。

with parentheses (*++argv)[0] : 带括号(*++argv)[0]

  1. ++argv increments the argv pointer to point to the next argument. ++argv将argv指针递增以指向下一个参数。
  2. * defereferences it to obtain a pointer to the character data. *取消引用它以获得指向字符数据的指针。
  3. [0] gets the first character in the character array. [0]获取字符数组中的第一个字符。

Yes, the two expressions differ (though only slightly). 是的,这两个表达式有所不同(尽管只有一点点)。 IMO, this code is a bit on the excessively clever side. IMO,此代码有点过于聪明。 You'd be better off with something like this: 最好使用以下方法:

for (int i=1; i<argc; i++)
    if (argv[i][0] == '-') {
       size_t len = strlen(argv[i]);
       for (int j=0; j<len; ++j)
           switch(argv[i][j]) {
               case 'x':
               // ...

This is pretty much equivalent to the code above, but I doubt anybody (who knows C at all) would have any difficulty figuring out what it really does. 这几乎等同于上面的代码,但是我怀疑任何人(完全了解C)是否会真正了解它的实际作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM