Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 铿锵++;vs g++;带越界引用的constexpr差_C++_C++17_Undefined Behavior_Constexpr_Clang++ - Fatal编程技术网

C++ 铿锵++;vs g++;带越界引用的constexpr差

C++ 铿锵++;vs g++;带越界引用的constexpr差,c++,c++17,undefined-behavior,constexpr,clang++,C++,C++17,Undefined Behavior,Constexpr,Clang++,我有consteprstd::array v1{0},v2{0}其行为类似于大整数。所以,我写了一个乘法函数来求数字的乘积 #包括 #包括 使用名称空间std; 模板 constexpr数组乘法(const数组&a, 常量数组(b){ 常数int as=N,bs=N,rs=as+bs; 数组结果{0}; __int128_t进位=0; 自动pr=开始(结果); 对于(int r=0,lim=min(rs,as+bs-1);r=as?as-1:r, j=r-i, k=i,如果0≤ i+j≤ n;否

我有
consteprstd::array v1{0},v2{0}其行为类似于大整数。所以,我写了一个
乘法函数来求数字的乘积

#包括
#包括
使用名称空间std;
模板
constexpr数组乘法(const数组&a,
常量数组(b){
常数int as=N,bs=N,rs=as+bs;
数组结果{0};
__int128_t进位=0;
自动pr=开始(结果);
对于(int r=0,lim=min(rs,as+bs-1);r=as?as-1:r,
j=r-i,
k=i
请注意,将乘法函数设置为最小值是不正确的

当我使用
clang++-std=c++17-Wall-O0 example.cc编译此代码时,我错误地得到:

example.cc:30:32: error: constexpr variable 'result' must be initialized by a constant expression
    constexpr array<int, 2 *N> result = multiply<N>(v1, v2);
                               ^        ~~~~~~~~~~~~~~~~~~~
example.cc:20:50: note: cannot refer to element -1 of array of 20 elements in a constant expression
            carry += static_cast<__int128_t>(*(pa--)) * (*(pb++));
                                                 ^
example.cc:30:41: note: in call to 'multiply(v1, v2)'
    constexpr array<int, 2 *N> result = multiply<N>(v1, v2);
                                        ^
1 error generated.
example.cc:30:32:错误:constexpr变量“result”必须由常量表达式初始化
constexpr数组结果=乘法(v1,v2);
^        ~~~~~~~~~~~~~~~~~~~
示例.cc:20:50:注意:无法在常量表达式中引用由20个元素组成的数组中的元素-1
进位+=静态_转换(*(pa-)*(*(pb++));
^
示例.cc:30:41:注意:在调用“乘法(v1,v2)”时
constexpr数组结果=乘法(v1,v2);
^
生成1个错误。
但这可以使用gcc正确编译。

为什么我认为clang的错误是一个错误:

为了验证是否存在越界访问,我启用了libstdc++的调试模式,并使用
g++-std=c++17-Wall-D_GLIBCXX_debug-g-O0 example.cc进行编译。如果存在越界访问,则不会发生崩溃

同样,在sanitizers(
g++-fsanize=address,undefined-fno省略帧指针)下,代码成功运行


我很好奇为什么clang声称可以越界访问,而实验清楚地表明情况并非如此。

clang是正确的。您没有发现错误

*(pa--)
假设
k
最初设置为
i+1
,在上次在
循环中计算此表达式之前,
pa
指向数组的第一个元素<代码>pa--
涉及评估
pa-1
,这会导致未定义的行为,根据:(
i=0
j=1

将具有整数类型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式
P
指向具有
n
元素的数组对象
x
的元素
x[i]
,则表达式
P+J
J+P
(其中
J
具有值
J
)指向(可能是假设的)元素
x[i+J]/code>,如果
0≤ i+j≤ n
;否则,行为是未定义的同样,表达式
P-J
指向(可能是假设的)元素
x[i]− j] 
if
0≤ 我− J≤ n
;否则,行为未定义。

现在,常量表达式不能计算:

本国际标准第[intro]条至第[cpp]条规定的具有未定义行为的操作

因此,
multiply(v1,v2)
不是一个常数表达式,这里需要诊断


当然,这个
[-1]
指针通常不会引起问题,除非您取消引用它,但它仍然是未定义的行为,这会阻止它成为常量表达式的一部分。消毒剂只能诊断有限的未定义行为子集。

为什么clang++-std=c++17-Wall-O0。。try-O3No崩溃并不意味着程序有效。UB只是没有定义。任何事情都有可能发生。(我不是说有UB,我只是说没有崩溃并不意味着没有)。@super,用
-D_GLIBCXX_DEBUG
编译会处理越界访问,而清理程序会处理未定义的行为。clang并不是在抱怨越界访问,它在抱怨创建指向数组外部的指针(它不在乎你没有取消对它的引用)。@Marglisse,如果是真的,那么这是一个大问题,因为我不应该为我没有做的事付费!警告应该足够了,但错误太多了!