简体   繁体   English

指向char指针与char指针的指针数组的指针(或char ** argv vs. char *(* argv)[])

[英]Pointer to array of pointer to char vs. pointer to pointer to char (or char** argv vs. char* (*argv)[])

I had a discussion with a colleague today regarding his (for me) unusual 'main' function signature. 今天,我与一位同事讨论了他(对我而言)不寻常的“主要”功能签名。 He likes to declare it like so: 他喜欢这样声明:

int main(int argc, char* (*argv)[]) {
   printf("at index 0: %s\n", (*argv)[0]);
}

while I usually write the following code: 而我通常编写以下代码:

int main(int argc, char** argv)
{
    printf("at index 0: %s\n", argv[0]);
}

Sometimes i write "char* argv[]", to make it more clear that argv is an array of pointers to chars. 有时我写“ char * argv []”,以便更清楚地表明argv是指向chars的指针数组。

The code in the first example does compile with a warning 第一个示例中的代码确实带有警告编译

warning: second argument of ‘main’ should be ‘char **’

but it works. 但它有效。 My question is WHY the code works, as I had expected a crash due to dereferencing argv. 我的问题是代码为什么能正常工作,因为我曾预计会由于取消引用argv而导致崩溃。 Does the compiler know that the function signature is different, and allows (*argv) as a kind of "no-operation" here? 编译器是否知道函数签名不同,并且在这里允许(* argv)作为一种“无操作”?

Trying to understand what's going on, I wrote the following example, which to my surprise does not crash either and prints "first" (but the compiler emits a warning): 为了理解正在发生的事情,我编写了以下示例,令我惊讶的是,该示例也没有崩溃也不会输出“ first”(但编译器会发出警告):

#include <stdio.h>

int my_function(int argc, char* (*argv)[])
{
    printf("at index 0: %s\n", (*argv)[0]);
}

int main(void)
{
    char* stringArr[] = { "frist",
                          NULL };
    size_t stringArrSz = sizeof(stringArr)/sizeof(*stringArr);

    return my_function(stringArrSz, stringArr);
}

I had expected that I would need to pass "&stringArr" (use the address operator) to make the code run. 我曾期望我需要传递“&stringArr”(使用地址运算符)来使代码运行。 That - of course - works too, and fixes the compiler warning. 当然,它也可以工作,并且可以修复编译器警告。

Please let my know if my question is unclear, any help is greatly appreciated! 如果我的问题不清楚,请告诉我,我们将不胜感激!

My question is WHY the code works, as I had expected a crash due to dereferencing argv. 我的问题是代码为什么能正常工作,因为我曾预计会由于取消引用argv而导致崩溃。 Does the compiler know that the function signature is different, and allows (*argv) as a kind of "no-operation" here? 编译器是否知道函数签名不同,并且在这里允许(* argv)作为一种“无操作”?

"Appearing to work as intended" is one of the possible outcomes of undefined behavior. “看起来像预期的那样工作”是不确定行为的可能结果之一。

A valid pointer value is still being passed for argv from the runtime environment, so I would not expect the code to crash just from accessing argv[0] , regardless of how it was declared. 有效的指针值仍在从运行时环境传递给argv ,因此我不希望代码仅由于访问argv[0]而崩溃,无论它如何声明。

Where things will get interesting is when you try to access argv[1] , argv[2] , etc. While the C language itself doesn't guarantee that pointers to different object types have the same size, in practice they do on most modern architectures like x86 ; 当您尝试访问argv[1]argv[2]等时,会变得有趣的地方。尽管C语言本身并不保证指向不同对象类型的指针具有相同的大小,但实际上,它们在大多数现代语言中都可以做到。像x86这样的x86 ; IOW, sizeof (T *) == sizeof (T **) == sizeof ( T *** ) . IOW, sizeof (T *) == sizeof (T **) == sizeof ( T *** ) Thus, p + 1 should yield the same byte offset for each of those types on that platform. 因此,对于该平台上的每种类型, p + 1应产生相同的字节偏移。

Your colleague is flirting with disaster, though. 但是,您的同事却在调情灾难。 Types do matter, and if you were working on a system where different pointer types had different sizes, declaring argv as char *(*)[] instead of char *[] or char ** could have some unexpected consequences. 类型确实很重要,如果您在不同指针类型具有不同大小的系统上工作,则将argv声明为char *(*)[]而不是char *[]char **可能会产生一些意外的后果。

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

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