小编MC *_* ΔT的帖子

为什么 memcpy 会导致编译器似乎忘记严格别名?

考虑以下 C++ 代码:

std::uint32_t func(std::uint32_t* p1, std::uint64_t* p2) {
    *p2 = *p1;
    return *p1;
}
Run Code Online (Sandbox Code Playgroud)

在 Clang 上编译会-O3产生以下反汇编结果(GCC 类似):

func(unsigned int*, unsigned long*):
        mov     eax, dword ptr [rdi]
        mov     qword ptr [rsi], rax
        ret
Run Code Online (Sandbox Code Playgroud)

(现场演示: https: //godbolt.org/z/vKPvT7o51

由于严格的别名规则,编译器假设p1p2不指向相同的内存位置,因此不需要*p1从内存中重新加载 return 语句。到目前为止一切顺利,优化正在按我的预期进行。


现在考虑一段类似的代码,其中复制是通过以下方式完成的memcpy()

std::uint32_t func(std::uint32_t* p1, std::uint64_t* p2) {
    std::memcpy(p2, p1, sizeof(std::uint32_t));
    return *p1;
}
Run Code Online (Sandbox Code Playgroud)

反汇编(在 Clang 和 GCC 上相同):

func(unsigned int*, unsigned long*):
        mov     eax, dword ptr [rdi] …
Run Code Online (Sandbox Code Playgroud)

c++ assembly gcc compiler-optimization language-lawyer

6
推荐指数
0
解决办法
460
查看次数

友元函数模板在类模板中返回推导的依赖类型的行为

我遇到过以下代码,其行为得到了 GCC、Clang 和 MSVC 的一致认可:

#include <concepts>

template<typename T>
auto foo(T);

template<typename U>
struct S {
    template<typename T>
    friend auto foo(T) {
        return U{};
    }
};

S<double> s;
static_assert(std::same_as<decltype(foo(42)), double>);
Run Code Online (Sandbox Code Playgroud)

现场演示: https: //godbolt.org/z/hK6xhesKM

foo()在全局命名空间中声明并推导返回类型。S<U>提供了 via 友元函数的定义foo(),它返回类型为 的值U

我期望的是,当S用 实例化时U=double,它的定义foo()被放入全局命名空间中U并被替换,由于友元函数的工作方式,有效地如下所示:

template<typename T>
auto foo(T);

S<double> s;

template<typename T>
auto foo(T) {
    return double{};
}
Run Code Online (Sandbox Code Playgroud)

因此我期望foo()的返回类型是double,并且以下静态断言应该通过:

static_assert(std::same_as<decltype(foo(42)), double>);
Run Code Online (Sandbox Code Playgroud)

然而,实际发生的情况是,所有三个编译器对此行为都持不同意见。

正如我所期望的,GCC 通过了静态断言。

Clang 失败了静态断言,因为它似乎相信 …

c++ templates language-lawyer c++20

6
推荐指数
1
解决办法
292
查看次数

防止 Visual Studio 在多行模板后缩进代码

我最近发现 Visual Studio 喜欢在占用多行的模板后面缩进内容,如下所示:
缩进类声明
在模板之后,我喜欢在不同的行上列出参数以防止出现一大行,类声明由制表符缩进。它缩进了整个类声明,因此可能有数百行最终不必要地缩进。

每次我使用 Visual Studio 的自动格式化工具时都会发生这种情况,这相当烦人,因为我确实希望能够使用自动格式化(它非常有帮助),但只是不是这个特定的“功能”(?)。我已经查看了“工具”->“选项”->“文本编辑器”->“C/C++”->“格式”中的所有选项,但尚未找到解决此问题的选项。

如何防止 Visual Studio 在这样的多行模板后缩进代码?

visual-studio visual-c++

5
推荐指数
0
解决办法
238
查看次数

类成员中内联函数的前向声明导致链接器错误

考虑以下代码:

struct Foo {
    float f;
    
    Foo& operator+=(Foo rhs) {
        Foo operator+(Foo, Foo);
        *this = *this + rhs;
        return *this;
    }
};

inline Foo operator+(Foo lhs, Foo rhs) {
    return Foo{lhs.f + rhs.f};
}
Run Code Online (Sandbox Code Playgroud)

当且仅当operator+(Foo, Foo)定义为 时inline,GCC 和 MSVC 会给出“未定义对 operator+(Foo, Foo) 的引用”链接器错误,而 Clang 没有问题。请参阅此处以获取实时示例。

我认为这段代码是有效的;inline函数的-ness 应该没有任何影响,因为函数不需要像inline定义为那样声明inline(无论如何,函数不能inline在块范围内声明)。
请注意,如果在 的定义之前operator+(Foo, Foo)改为声明(为非inlineFoo,则所有 3 个编译器都接受它。

但是,标准中的诸如链接之类的问题很棘手,所以我知道它也可能是未定义的行为或“格式错误,无需诊断”,而 GCC 和 MSVC 恰好会出错。

那么这个代码有效吗?哪个编译器是正确的?

c++ language-lawyer

5
推荐指数
0
解决办法
145
查看次数

具有单个 char 数组成员的结构是否保证具有可预测的大小?

考虑以下结构:

struct alignas(8) Foo {
    char data[8];
};
Run Code Online (Sandbox Code Playgroud)

标准是否保证这一点sizeof(Foo) == 8

从外行人的角度来看,这应该是正确的,因为 8char不需要任何填充即可对齐为 8。并且在 GCC、Clang 和 MSVC 上的实践中似乎也是如此(现场演示)。

然而,填充和对齐是一件棘手的事情,我找不到任何严格禁止实现添加无关填充的信息 - 即也sizeof(Foo) == 16可能吗?

到目前为止我发现了以下内容:

  • sizeof(char[8]) == 8是有保证的(见这里),因此sizeof(Foo) >= 8)
  • Foo没有前导填充,因为它是标准布局类型(请参见此处
  • 至少有一个更有知识的人 - 作者std::bit_cast- 显然认为没有填充 -请参阅这篇文章

(有趣的是,如果这个事实不正确,则似乎意味着结构可以具有任意大的大小,这有点奇怪。)

c++ language-lawyer c++20

2
推荐指数
1
解决办法
203
查看次数