首页 > 解决方案 > const-promotion 在哪里定义

问题描述

我正在寻找在 c/c++ 中定义 const-promotion 的位置。这是一个隐式转换,但我找不到任何文档。

这适用于 g++,同时使用 --pedantic 标志

// prototypes for example
void foo(char*);
void bar(const char*);

char buffer[8];
snprintf(buffer,sizeof(buffer), "hello");

// note: string literals are of type const char*

foo(buffer);
foo("hello"); // works, but why
bar(buffer);
bar("hello");

上面表示的行为是预期的行为。但是我正在寻找这种行为的文档。我查看了(草稿)c++98 标准和堆栈溢出搜索“提升”和“隐式转换”,但没有找到答案。

如果这个问题太宽泛,我使用的是 C++98,所以我们可以针对该标准来解决它。

标签: c++clanguage-lawyerc++98

解决方案


这个答案适用于 C 而不是 C++。

char根据 C 2018 6.4.5 6 1 ,字符串文字(区别于 UTF-8 字符串文字或宽字符串文字)是 的数组。由于历史原因,它们不是 的数组const char,但const程序员应该将它们视为,如果程序尝试写入字符串文字,则行为未由 C 标准定义。

作为数组,字符串文字会自动转换为char *指向其第一个元素的 a,除非它是sizeof或一元的操作数或&用于初始化数组。

因此,在foo(buffer)foo("hello")中,我们都有一个char *参数传递给一个char *参数,并且不需要转换。

bar(buffer)andbar("hello")中,我们有一个char *参数传递给一个const *参数。对此的解释如下。

对于原型可见的函数调用,根据 C 2018 6.5.2.2 7,参数将转换为参数的类型,就像通过赋值一样:

如果表示被调用函数的表达式具有包含原型的类型,则参数被隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为其声明的非限定版本输入……</p>

(请注意,“其声明类型的非限定版本”表示const intorchar * const参数将分别是intchar *,而不是const char *参数将是char *。)

6.5.16.1 2 说:

在简单赋值(=)中,右操作数的值被转换为赋值表达式的类型……</p>

赋值表达式的类型是左操作数的类型,6.5.16 3:

…赋值表达式的类型是左操作数在左值转换后的类型…</p>

所以现在我们知道char *被转换为const char *. 这也满足了 6.5.16.1 1 中的分配约束:

以下其中一项应成立:……左操作数具有原子、合格或非限定指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的合格或非限定版本的指针,并且左侧指向的类型具有右侧指向的类型的所有限定符;…</p>

并且在 6.3.2.3 2 中指定了指针转换:

对于任何限定符q,指向非q限定类型的指针可以转换为指向该类型的q限定版本的指针;存储在原始指针和转换指针中的值应比较相等。

对于snprintf调用,参数在参数"hello"中对应的位置传递...。为此,我们查看 6.5.2.2 7 的其余部分,从上面引用的第一部分继续:

... 函数原型声明器中的省略号符号导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

默认参数提升在 6.5.2.2 6 中:

…整数提升在每个参数上执行,具有浮点类型的参数被提升为双精度。这些被称为默认参数提升

这些提升不会影响指针,因此指针在其类型不变的情况下传递。这很有趣,因为我们可以在这里传递 achar *或 a const char *。的规范是snprintffprintf,对于%s规范,在 7.21.6.1 8 中说:

...参数应该是指向字符类型数组的初始元素的指针。...</p>

所以它只需要一个指向“字符类型”的指针,而不是特定类型,例如charorconst charvolatile char

(我们可能会进一步想知道,如果我们要实现自己的函数 likesnprintf和 using<stdarg.h>来执行它,传递char *参数并使用宏调用处理它va_arg(ap, const char *)是否可行。我最初阅读va_arg7.16.1.1 2 中的规范说类型必须可以兼容,但是char *const char *不兼容,不过这个我没研究透。)

脚注

1从技术上讲,字符串字面量是源代码中的一个事物或在 C 翻译阶段它的表示形式,它用于创建一个char. 为简单起见,我将数组称为字符串文字。


推荐阅读