【问题标题】:const char const *char[] compiler warningconst char const *char[] 编译器警告
【发布时间】:2016-05-29 16:03:40
【问题描述】:

我正在学习 C 语言,但我还不太熟悉,但我正在学习一些课程,并且我收到了关于重复的“const”声明说明符的编译器警告。

违规行是;

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

除非我严重误解了 const 在参数定义中的工作方式,因为 argv 是我需要使用的数组;

int main(int argc, const char const **argv)

或许

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

编译器不会抱怨这些选项中的任何一个,如果我的想法是正确的,那么两者都应该产生相同的结果,因为 *argv[] 是指向数组的指针。我意识到如果 argv 不是数组,它们会有不同的含义,但是在这种特殊情况下,它们产生相同的结果并且它们是正确的声明而不是原始声明,我错了吗?

【问题讨论】:

  • argv可以修改,不一定是const,也许你在找const char *const pointer,其中第一个const表示指向的数据是const,第二个意味着指针本身是 const 的,即它不能指向其他任何东西,只能指向它的原始值。
  • 不,从技术上讲,它们并不相同。第一个sn-p是char *的数组,第二个是双指针。
  • @RPGillespie 你有很多东西要学。使用第一个 sn-p(不带 const),尝试 for (int i = 0; i < argc; i++) printf( "%s\n", *argv++ ); 并查看编译器对此有何评论(无),以及它是否有效(有效)。点是,即使参数被指定为一个指针数组,它实际上是一个双指针。
  • @fanton 不,当char *p[] 作为函数参数出现时不会。在其他情况下,当然可以。
  • @RPGillespie C 标准在函数参数列表中定义它们完全相同。在 C 中无法按值传递数组

标签: c arrays pointers char constants


【解决方案1】:

在这一行:

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

你写了两次const。一般来说,这是 C 标准允许的,但无论如何,您的编译器似乎是友好的和警告的。您可以忽略或禁用此警告,或删除consts 之一。

但是,main 是特殊的:在这里使用const 是非标准的。应该是:

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

编译器可能接受也可能不接受带有const 的版本。是否这样做是实现定义的,这意味着编译器的文档应该有一个页面来讨论它接受哪些main 的签名。

【讨论】:

  • 我意识到语法对于普通的 int main 定义来说是非标准的,实际上我并没有编写代码,这是我正在学习的其他人编写的课程。我仍在研究整个程序,以了解程序中完成许多事情的原因。我怀疑 const 修饰符存在,因为 APR 函数正在使用 argv,但我还没有做到这一点。是否存在在类型之前和所述类型的指针之前同时使用 const 修饰符的某些情况?
  • @JackGalt 不,这些都是相同的上下文(限定符和类型的顺序没有区别,只要你不重新排序超过 *,你甚至可以写 const int const long const long const 而不是const long long 如果你愿意)
  • 谢谢!这有助于在很大程度上澄清事情,并且您节省了我一些时间来尝试理解代码错字在做什么。如果编译器完全拒绝了它,我会立即明白这是错误的。我看过其他双重使用 const 的代码示例,所以我认为这是有原因的,我显然一直在追我的尾巴。
【解决方案2】:

除非我严重误解了 const 在参数定义中的工作方式,因为 argv 是我需要使用的数组

int main(int argc, const char const **argv)

或许

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

那么显然,您严重误解了const 在参数定义中的工作方式。我们稍后会谈到这一点,但首先我注意到main() 的允许签名由标准指定。允许实现支持额外的签名,但符合要求的“托管”实现需要支持的是:

int main(void)

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

和等效项 (C2011, 5.1.2.2.1)。因此,不管所有其他考虑因素如何,这些签名都是受支持的,并且不需要支持不等价的签名,例如带有 const 限定符的签名。

然后,回到数组参数的问题。假设你有一个数组...

int a[4];

... 你想传递给一个函数。从技术上讲,你做不到。在几乎所有情况下,尤其是当它们作为函数参数出现时,数组值衰减 到指针。您可以传递这样的指针,这确实很常见,但您不能传递数组本身。数组的元素类型,包括完全相同的限定符,是结果指针值的目标类型。此外,values 不能是const——这是类型的属性。这样写就很好了

int a[4];
int f(int *);

f(a);

此外,请注意,您提出的两个方法签名都将参数argv 声明为指向const char 的指针。该类型与指向char 的指针不兼容。如果您想声明 argv 本身不能更改(尽管这样做是不必要的),那么您可以将其写为

int main(int argc, char ** const argv)

,我怀疑你的编译器会接受。如果你想声明argv 数组中的指针不能通过argv 改变,那么就是...

int main(int argc, char * const *argv)

... 这也很有可能被接受。但是,您实际尝试编写的内容将argv 元素的内容 声明为const,这是不兼容的。

【讨论】:

    【解决方案3】:

    const 适用于其紧邻的左侧,除非左侧没有任何东西,否则它适用于其紧邻的右侧。所以声明:

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

    将两个const 应用于同一个char 标识符,因此出现警告。

    如果你想说argv 是一个指向常量字符的非常量指针数组,使用这个:

    const char * argv[]
    

    如果你想说argv 是一个指向常量字符的常量指针数组,使用这个:

    const char * const argv[]
    

    argv 参数的正确声明就是char* argv[]char** argv。根本没有使用 const 说明符。特定的编译器可能允许const 变体,但标准没有定义。

    【讨论】: