相关疑难解决方法(0)

不同的优化级别可以导致功能不同的代码吗?

我很好奇编译器在优化时的自由度.让我们将这个问题限制在GCC和C/C++(任何版本,任何标准版本):

是否有可能根据编译的优化级别编写行为不同的代码?

我想到的例子是在C++中的各种构造函数中打印不同的文本位,并根据副本是否被删除而获得差异(尽管我无法使这样的东西工作).

不允许计数时钟周期.如果你有一个非GCC编译器的例子,我也很好奇,但我无法检查它.C中的示例的奖励积分:-)

编辑:示例代码应该是标准兼容的,并且从一开始就不包含未定义的行为.

编辑2:已经有了一些很棒的答案!让我稍微了解一下:代码必须构成一个格式良好的程序并且符合标准,并且必须在每个优化级别编译为正确的,确定性的程序.(这不包括形状不规则的多线程代码中的竞争条件等.)我也理解浮点舍入可能会受到影响,但让我们对此进行折扣.

我只获得了800点声望,所以我认为我将在第一个完整的例子中赢得50点声望以符合这些条件的(精神); 25如果涉及滥用严格别名.(视某人向我展示如何向他人发送赏金.)

c c++ gcc compiler-optimization

44
推荐指数
6
解决办法
4456
查看次数

可以将不同的GCC方言联系在一起吗?

我知道原则上这可能是未定义的行为,但为了处理大型项目,这里是关于GCC的问题:

假设我使用完全相同的编译器安装编译一个转换单元gcc -std=c++98,另一个-std=c++11使用.是否有任何保证可以链接两个目标文件并获得定义良好的程序?

据我所知,由于不同的宏,潜在的问题只能来自库头的不同视图,而这些问题反过来最多只能新的成员函数添加到标准库类中,而不是成员对象.

这会以某种方式使用不同的语言方言选项编译更大项目的不同部分是否可以接受?

更新:我应该添加一个正交的问题:如何使用两个不同版本的GCC(比如4.3和4.6),但是同一个方言选项(-std=c++98)?此GCC文档中的列表似乎表明该库在4.2.2和4.6之间兼容.

c++ linker gcc undefined-behavior dialect

18
推荐指数
1
解决办法
687
查看次数

链接gcc 6,gcc 7和gcc 8对象安全吗?

链接C ++ 17,C ++ 14和C ++ 11对象是否要求链接使用不同语言标准编译的对象是否安全,而Jonathan Wakely在该问题上的出色回答解释了gcc / libstdc ++做出的ABI稳定性承诺确保这行得通。

不过,在gcc版本之间还有另一件事可以更改-语言ABI通过-fabi-version。假设,为简单起见,我有三个目标文件:

  • foo.o,使用gcc 6.5 c ++ 14编译
  • bar.o,使用gcc 7.4 c ++ 14编译
  • quux.o,使用gcc 8.3 c ++ 17编译

全部具有各自的默认语言ABI(即10、11和13)。从库的角度来看,根据链接的答案将这些对象链接在一起是安全的。但是从语言ABI的角度来看是否存在可能出错的事情?我有什么需要注意的吗?大多数语言ABI更改似乎都不会引起问题,但是12中的空类类型的调用约定更改可能吗?

c++ gcc c++17

17
推荐指数
2
解决办法
644
查看次数

C++ 11与现有库/框架的兼容性

我想知道一些我还没有找到令人信服的答案的东西.

情况:

  • 在没有启用c ++ 11的情况下编译的具有一些库(例如gtkmm)的系统.
  • 启用了C++ 11编译的应用程序.
  • 两者都编译并链接到相同的GCC版本/环境.
  • 应用程序对库使用std :: string和std :: vector进行了一些函数调用.

std :: string和std :: vector都支持移动语义,这很可能意味着它们与非C++ 11变体不是二进制兼容的.但是应用程序和库都使用相同的编译器和标准库构建,因此如果lib能够识别并支持它,那就不会那么奇怪了.

上述情况是否安全,或者是否真的需要使用C++ 11标志编译所有内容,即使使用相同的构建环境?

c++ shared-libraries c++11

10
推荐指数
1
解决办法
1068
查看次数

静默gcc的“仅在-std = c ++ XX或-std = gnu ++ XX时可用”警告

更高语言版本中的某些语言功能非常有用,并且编译器供应商已选择将它们反向移植到较早版本。最典型的例子是if constexpr

这个简单的程序:

template <typename T>
constexpr int get() {
    if constexpr (sizeof(T) > 10) {
        return 1;
    } else {
        return 0;
    }
}

static_assert(get<int>() == 0, "!");
static_assert(get<char[100]>() == 1, "!");
Run Code Online (Sandbox Code Playgroud)

从技术上讲,按照语言规则需要C ++ 17,并且在C ++ 11中从技术上来说是格式错误的……但是gcc和clang都可以正常编译它-std=c++11。每个发出警告。

Clang告诉您该警告是什么,因此您可以将其禁用:

foo.cxx:3:8: warning: constexpr if is a C++17 extension [-Wc++17-extensions]
    if constexpr (sizeof(T) > 10) {
       ^
1 warning generated.
Run Code Online (Sandbox Code Playgroud)

使用clang进行编译-Wno-C++17-extensions不会产生警告。

但是gcc实际上并没有说出警告的来源:

foo.cxx: In function ‘constexpr int get()’:
foo.cxx:3:8: warning: ‘if constexpr’ only available with -std=c++17 …
Run Code Online (Sandbox Code Playgroud)

c++ g++ c++11 c++17

8
推荐指数
1
解决办法
321
查看次数

在std :: filesystem :: path追加上的c ++ std :: bad_alloc

我遇到一个非常奇怪的行为,我将其提炼为一个非常基本的测试:

#include <string>
#include <filesystem>

int main(void)
{
  const std::string name = "foo";
  const std::filesystem::path lock_dir = "/tmp";
  std::filesystem::path lockfile = lock_dir / name;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用编译g++ -std=c++17 -Wall -Wextra -Werror -g foo.cpp -o foo。当我运行它时,在添加两个路径的那一行上,我得到了一个std :: bad_alloc异常。这是我在gdb中看到的

#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff742c801 in __GI_abort () at abort.c:79
#2  0x00007ffff7a8e1f2 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7a99e36 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff7a99e81 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff7a9a0b5 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 …
Run Code Online (Sandbox Code Playgroud)

c++ gdb exception libstdc++ c++17

8
推荐指数
1
解决办法
336
查看次数

Boost和C++之间的互操作性11

C++ 11与使用C++ 11编译器构建的最新版Boost(比如说1.55)之间的互操作性程度如何?

  1. 任何库功能的行为是否会根据我是否使用c ++ 11标志构建库来改变?
  2. lambda函数等语言特性如何与Boost的lambdas合作?

c++ boost c++11

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

libstdc ++的make_shared布局是否在gcc 4.x和gcc 6.x之间发生了变化?

请考虑以下最小示例,包含三个文件:

foo.h:

#pragma once
#include <memory>

struct X {
    uint64_t i = 0xdeadbeefdeadbeefULL;
};

void foo();
Run Code Online (Sandbox Code Playgroud)

foo.cxx:

#include "foo.h"

void foo() {
    std::make_shared<X>();
}
Run Code Online (Sandbox Code Playgroud)

main.cxx:

#include <memory>
#include "foo.h"

template std::shared_ptr<X> std::make_shared();

int main() {
    foo();
}
Run Code Online (Sandbox Code Playgroud)

然后使用不同版本的gcc编译两个翻译单元:

$ g++-4.8.2 -g -std=c++11 -O0 -c foo.cxx -o foo.o
$ g++-6.2.0 -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -O0 -g main.cxx foo.o -fsanitize=address -fno-omit-frame-pointer
Run Code Online (Sandbox Code Playgroud)

请注意,我是专门用旧的ABI编译的.

运行生成的可执行文件(如果两个TU都使用相同版本的gcc编译,则不会):

==33535==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff8 at pc 0x000000401dcf bp 0x7fffffffd7f0 sp 0x7fffffffd7e8
WRITE of size 8 at …
Run Code Online (Sandbox Code Playgroud)

c++ gcc g++ abi libstdc++

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

链接到 C++ 库时出现意外的符号解析

我正在构建一个基于两个对象(add.o 和 sub.o)的库“libsimplemath.a”。

主要只依赖于 add.o 接口。当代码与 libsimplemath.a 链接时,我希望它可以工作。

在构建 libsimplemath.a 时,我决定将 -std 标志从 c++14 切换到 c++17。在这一点上,由于某些原因 sub.o 也由链接器带来,并且因为它包含未定义的符号链接失败。

要了解为什么 sub.o 被考虑在内,可以查看链接器映射文件:

Archive member included to satisfy reference by file (symbol)

    ./libsimplemath.a(add.o)      main.o (add(int, int))
    ./libsimplemath.a(sub.o)      main.o (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string())
    /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
                                  /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/Scrt1.o (__libc_csu_init)
Run Code Online (Sandbox Code Playgroud)

一些 stl 符号,这里的 ~basic_string() 在 sub.o 中解析。

问题是:即使没有明确使用 sub.o 也会被考虑在内吗?如果是这样,我目前正在做的事情有什么问题?

语境:

$ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.32
Run Code Online (Sandbox Code Playgroud)

添加.cpp

int add(int a, int b) { return a …
Run Code Online (Sandbox Code Playgroud)

c++ linker compilation

5
推荐指数
1
解决办法
79
查看次数

我可以安全地混合使用 -std=c++11 和 -std=c++14 编译的库吗?

从 C++98 和 C++11 过渡的早期开始,我记得在将 C++98 库和 C++11 库链接在一起时出现了一些与 ABI 相关的问题。(参见例如将不同的 C++ 标准与 GCC 混合以及该问题的答案。)

我有一个特殊的情况,我的代码的一部分需要使用仅支持 C++11 的工具进行编译,而另一部分使用 C++14 特性并且可以使用支持它们的标准 g++ 进行编译。我可以将代码的每一部分放入自己的库中并链接它们。但我想知道:一般来说,C++11 和 C++14 之间是否存在会导致(例如 ABI 相关)问题的差异?

c++ c++11 c++14

4
推荐指数
1
解决办法
1025
查看次数