c++ - 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 而不是 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 int
orchar * const
参数将分别是int
或char *
,而不是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 *
。的规范是snprintf
指fprintf
,对于%s
规范,在 7.21.6.1 8 中说:
...参数应该是指向字符类型数组的初始元素的指针。...</p>
所以它只需要一个指向“字符类型”的指针,而不是特定类型,例如char
orconst char
或volatile char
。
(我们可能会进一步想知道,如果我们要实现自己的函数 likesnprintf
和 using<stdarg.h>
来执行它,传递char *
参数并使用宏调用处理它va_arg(ap, const char *)
是否可行。我最初阅读va_arg
7.16.1.1 2 中的规范说类型必须可以兼容,但是char *
和const char *
不兼容,不过这个我没研究透。)
脚注
1从技术上讲,字符串字面量是源代码中的一个事物或在 C 翻译阶段它的表示形式,它用于创建一个char
. 为简单起见,我将数组称为字符串文字。
推荐阅读
- c# - 如何更改节点 Json 的所有值并返回相同的对象动态?
- javascript - 如何检查对象是否具有相同的属性然后计算总数
- flutter - 颤振)有没有办法清除仅推送到某个部分的堆栈?
- r - 在 R 中按组添加一列,计算行数直到第一个 1
- python - 如何使用 Pandas DataFrame 修改带有条件的 Excel 行?
- c - 为什么 Visual Studio 给我错误但使用 cl.exe 编译可以正常工作?
- swift - DispatchQueue.main.async 挂起后重复,但使用睡眠时不挂起
- python - 为什么添加 hline 或 vline 时 Plotly / Dash 混合图形和表格子图会中断?
- python - 为什么 dataframe.plot 的错误栏不显示?
- amazon-web-services - 为了不被 AWS 收费,我应该删除哪些 IAM 角色和策略?