仅当在 static_cast
中使用时,即使启用了大多数警告选项,GCC 才会警告
越界数组访问。
示例代码(live):
#include <iterator>
#include <numeric>
#include <print>
int main()
{
int arr[ 5 ] { };
std::iota( std::begin( arr ), std::end( arr ), 1 );
// <no warning> -<warning>-----
std::println( "{} at address: {:p}", *(arr - 1), static_cast<const void*>(&( *(arr - 1) )) );
// <no warning> -<warning>-
std::println( "{} at address: {:p}", arr[ -1 ], static_cast<const void*>(&arr[ -1 ]) );
int* const ptr { arr + 2 };
// <no warning> -<warning>-
std::println( "{} at address: {:p}", ptr[ -3 ], static_cast<const void*>(&ptr[ -3 ]) );
}
编译器输出:
<source>: In function 'int main()':
<source>:12:54: warning: array subscript -1 is outside array bounds of 'int [5]' [-Warray-bounds=]
12 | std::println( "{} at address: {:p}", *(arr - 1), static_cast<const void*>(&( *(arr - 1) )) );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:9: note: at offset -4 into object 'arr' of size 20
8 | int arr[ 5 ] { };
| ^~~
<source>:14:78: warning: array subscript -1 is below array bounds of 'int [5]' [-Warray-bounds=]
14 | std::println( "{} at address: {:p}", arr[ -1 ], static_cast<const void*>(&arr[ -1 ]) );
| ^~~~~~~~~~
<source>:8:9: note: while referencing 'arr'
8 | int arr[ 5 ] { };
| ^~~
<source>:18:53: warning: array subscript -1 is outside array bounds of 'int [5]' [-Warray-bounds=]
18 | std::println( "{} at address: {:p}", ptr[ -3 ], static_cast<const void*>(&ptr[ -3 ]) );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:9: note: at offset -4 into object 'arr' of size 20
8 | int arr[ 5 ] { };
| ^~~
例如,我自然也希望看到
*(arr - 1)
的警告。但显然,只有 static_cast
中的表达式(例如 &( *(arr - 1) )
)才会被迂腐地检查是否存在无效访问。
这是 GCC 中的错误吗?因为代码非常简单且明确。我希望编译器至少在这种简单的场景中显示警告。
注意:Clang 更糟糕,仅警告
arr[ -1 ]
。
这些警告仅在启用优化时才会出现。优化器中发生的抽象解释允许它在编译时检测一些运行时错误。
在这种情况下,您将表达式作为 可变参数 传递,因此尽管您已转换为 const 指针,但
println()
不承诺遵守这一点 - 可变参数在定义的编译时没有特定类型。因此,编译器会看到您正在传递一个“常量指针”,接收函数可能会引用并写入该指针。造成这种情况的不是static_cast
,而是夺取地址
&
。强制转换必须符合格式说明符。在表达式 *(arr-1)
的情况下,它是读取访问并按值传递(而不是指针),尽管您可能不会获得有用的结果,但您不会修改我们的边界位置 - 因此需要注意警告关于。
您可以使用以下表达式简化测试以证明该行为与静态转换无关:int x = *(arr-1) ; // No warning - out of bounds read
*(arr-1) = 0 ; // warning: array subscript 4611686018427387903 is above array bounds of 'int [5]'
int* p = &(*(arr-1)) ; // no warning, juts taken the address, not written to.
*p = 2 ; // warning: array subscript -1 is outside array bounds of 'int [5]'