给定一个 C++11 编译器,#error它最终应该使用哪个正确的编译器?
// no #includes!
#define SOMEMACRO true
#if SOMEMACRO
#error "it was true"
#else
#error "it was false"
#endif
Run Code Online (Sandbox Code Playgroud)
显然我#error只是作为测试使用。我知道true并false以适当的语言定义,但这是预处理器上下文。在 C99 中,它似乎不被预处理器识别。
我问是因为似乎我尝试过的所有编译器都将其视为“真”,而静态代码分析工具坚持认为true未定义,隐含错误并以“它是假的”结束。
在 C++11 constexpr 函数中,assert()不可能使用第二个语句,例如 an 。Astatic_assert()很好,但如果该函数被称为“正常”函数,则它不起作用。逗号运算符可以来帮助wrto。的assert(),而是丑陋和一些工具吐出它的警告。
考虑这样的“getter”,它在断言旁边是完全可构造的。但是我想为运行时和编译时保留某种断言,但不能仅根据“constexpr”上下文进行重载。
template<int Size>
struct Array {
int m_vals[Size];
constexpr const int& getElement( int idx ) const
{
ASSERT( idx < Size ); // a no-go for constexpr funcs in c++11
// not possible, even in constexpr calls as being pointed out, but what I would like:
static_assert( idx < Size, "out-of-bounds" );
return m_vals[idx];
}
};
Run Code Online (Sandbox Code Playgroud)
附带条件:C++11,无堆,无异常,无编译器细节。
注意正如评论者指出的那样(谢谢!),static_assert论点是不可能的(但会很好)。在这种情况下,编译器在越界访问时给了我一个不同的错误。
使用宽松的存储顺序,例如对于引用计数指针,是否允许编译器优化掉后续的递增和递减?
std::atomic_int32_t ai;
for (size_t i = 0; i < 10000; i++)
{
ai.fetch_add(1, std::memory_order_relaxed);
ai.fetch_sub(1, std::memory_order_relaxed);
}
Run Code Online (Sandbox Code Playgroud)
看看反汇编它看起来不像.但是由于允许重新排序并且atomic行为类似于计数器,只是线程安全,人们可以争辩说他可以优化,好像它是一个普通的int.
tl;dr:能否以某种方式确保(例如通过编写单元测试)某些东西被优化掉,例如整个循环?
确保生产版本中不包含某些内容的常用方法是将其包装为#if...#endif. 但我更喜欢继续使用 C++ 机制。即使在那里,我也喜欢保持简单的实现,而不是复杂的模板专业化,并认为“嘿,编译器无论如何都会优化它”。
上下文是汽车中的嵌入式软件(二进制大小很重要),编译器通常很差。它们在安全意义上得到了认证,但通常在优化方面表现不佳。
示例 1:在容器中,元素的销毁通常是一个循环:
for(size_t i = 0; i<elements; i++)
buffer[i].~T();
Run Code Online (Sandbox Code Playgroud)
这也适用于内置类型,例如int,因为标准允许显式调用任何标量类型的析构函数 (C++11 12.4-15)。在这种情况下,循环不执行任何操作并被优化掉。在 GCC 中是这样,但在另一个(Aurix)中不是,我在反汇编中看到了一个字面上的空循环!因此需要模板专门化来修复它。
示例 2:代码,仅用于调试、分析或故障注入等:
constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
if( isDebugging ) {
// Albeit 'dead' section, it may not appear in production binary!
// (size, security, safety...)
// 'if constexpr..' not an option (C++11)
std::cout << "Arg was " << arg << std::endl;
}
// …Run Code Online (Sandbox Code Playgroud) 我们在我们的大项目中有中心类和函数来从实际的平台类型中抽象出来,例如互斥锁、文件、线程等,而不是在代码中到处都有“fopen”。虽然这很好,但我想更进一步,头文件中不包含任何系统(如#include <windows.h>),这将是真正的平台抽象和更快的编译。不利的一面是,您不能仅将 typedef 定义为系统类型(例如 Windows HANDLE)。
class RwMutex
{
// .....
private:
struct Impl;
Impl* m_Impl;
}
Run Code Online (Sandbox Code Playgroud)
class RwMutex {
public:
bool LockRead() {return RwMutexLockRead( this );}
private:
char m_AnonymousMember[ 16 ];
}
bool RwMutexLockRead( RwMutex* p );
Run Code Online (Sandbox Code Playgroud)
也许我很渴望它,但是如果大量的项目代码可以清除任何依赖于平台的包含(可能由-nostdinc选项强制执行),那就太酷了。
我正在努力将地址映射到它们的符号以进行调试(获取callstack).该MS dbghelp.dll可以从地址(见告诉符号SymFromAddr,MSDN).但是,它不起作用,我想知道这是如何工作的,因为地址似乎随着程序的每次运行而改变:
#include <iostream>
void Foo() {}
int _tmain(int argc, _TCHAR* argv[])
{
const long unsigned int addr = reinterpret_cast<long unsigned int>(&Foo);
std::cout << "Address: " << std::hex << addr << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
D:\dev\Sandbox\Debug>Sandbox.exe
Address: 901320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: ce1320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: 3a1320
D:\dev\Sandbox\Debug>Sandbox.exe
Address: 3f1320
Run Code Online (Sandbox Code Playgroud)
一个不同的程序如何从堆栈跟踪中读取地址并将其映射到函数?这对我来说听起来很神奇.我没有在链接文档中找到任何说明我必须从地址或其他内容中减去一些内容的内容.
根据我的理解,因为我们克服了实模式,所以每个进程都有一个虚拟内存空间,所以不需要再为掷骰子加载地址了.我会理解DLL的绝对地址的不确定性,但不是主要的可执行文件.
用VS2008试用Win7.
我想检测我是否已经看到了一个文件,并且想用一些独特的东西来识别它。在 Linux 下,有 inode 编号和设备 ID(请参阅stat()或fstat())。我想在 Windows 下我会找到类似的东西。
为了简单起见,它boost::filesystem提供了方便的方法,例如我可以用来boost::filesystem::recursive_directory_iterator遍历目录树。它file_status告诉我它是否是一个常规文件,但不是 inode 号。
我发现的最接近的事情是boost::filesystem::equivalent()走两条路。我想这也是最便携的设计。
问题是我想将索引节点号放入数据库中以便快速查找。我无法使用此函数执行此操作,我必须调用equivalent()数据库中已存在的所有路径。
我是否运气不好,由于可移植性原因,Boost 不会向我提供此类信息?
(编辑)目的是在文件夹树的一次扫描期间通过硬链接检测重复项。equivalent()正是这样做的,但我必须做一个二次算法。
也许这太明显了,但我还没有看到答案:
我尝试在 Ubuntu 下使用 clang 编译我的项目,但不幸的是 llvm 因堆栈转储而崩溃。
$ clang --version
Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)
Target: i386-pc-linux-gnu
Thread model: posix
Run Code Online (Sandbox Code Playgroud)
我想尝试一下 LLVM 2.9,安装了它,但我该如何选择它?例如:
$ ll /usr/bin/llvm-ar*
lrwxrwxrwx 1 root root 27 Sep 12 16:43 /usr/bin/llvm-ar -> ../lib/llvm-3.1/bin/llvm-ar*
lrwxrwxrwx 1 root root 27 May 21 2012 /usr/bin/llvm-ar-2.9 -> ../lib/llvm-2.9/bin/llvm-ar*
lrwxrwxrwx 1 root root 27 Aug 27 20:31 /usr/bin/llvm-ar-3.0 -> ../lib/llvm-3.0/bin/llvm-ar*
lrwxrwxrwx 1 root root 27 Aug 28 17:49 /usr/bin/llvm-ar-3.1 -> ../lib/llvm-3.1/bin/llvm-ar*
$ ll /usr/bin/clang*
-rwxr-xr-x 1 …Run Code Online (Sandbox Code Playgroud) 对于std::bitset我使用的(std forbidden)自己的实现uint_fast32_t,因为它在64位CPU上更快.评论说明是节省小集的空间,例如bitset <6>不应该使用8个字节.如果考虑结构中的对齐,浪费甚至更多.
使用C++ 11很好.我想优雅地选择:
作为我班级的存储类型:
template<size_t Size>
struct BitSet {
typedef <expression> StorageType;
// an array of that storage type...
};
Run Code Online (Sandbox Code Playgroud)
我可以想到相当笨拙的助手模板,但也许在C++ 11中有更优雅的东西.
编辑:澄清:uint_fast8_t对于原始类会很好,编译器可以选择快速的任何东西.想象一下尺寸== 1000000.但是在某些机器上它会是64位,并且当某些用例中的大小很重要时,例如Size == 4,这意味着会浪费7个字节.
我在我们的代码库中看到了两种风格。简单的问题:更喜欢什么?
void
someNsName::someFunc( int a, int b )
{/*...*/}
void
someNsName::someOtherFunc( int c )
{/*...*/}
Run Code Online (Sandbox Code Playgroud)
或者
namespace someNsName {
void
someFunc( int a, int b )
{/*...*/}
void
someOtherFunc( int c )
{/*...*/}
} // NS someNsName
Run Code Online (Sandbox Code Playgroud)
我个人更喜欢后者,尤其是当您必须从someNsName其他方面获得很多资格时。但还有更多原因吗?
c++ ×9
c++11 ×5
assert ×1
atomic ×1
boost ×1
c ×1
clang ×1
constexpr ×1
dead-code ×1
llvm ×1
namespaces ×1
preprocessor ×1
templates ×1
unit-testing ×1