小编Myr*_*ria的帖子

将模块化安全地乘以无符号整数的最佳C++方法是什么?

比方说,你正在使用<cstdint>和类型,如std::uint8_tstd::uint16_t,和想要做的操作,如+=*=他们.你喜欢对这些数字进行算术运算,就像在C/C++中一样.这通常工作,你会发现与实验工作std::uint8_t,std::uint32_tstd::uint64_t,但不std::uint16_t.

具体而言,乘法std::uint16_t有时会失败,优化的构建会产生各种奇怪的结果.原因?由于有符号整数溢出导致的未定义行为.编译器基于未发生未定义行为的假设进行优化,因此开始从程序中修剪代码块.具体的未定义行为如下:

std::uint16_t x = UINT16_C(0xFFFF);
x *= x;
Run Code Online (Sandbox Code Playgroud)

原因在于C++的推广规则以及你和其他几乎所有人一样使用平台的事实std::numeric_limits<int>::digits == 31.也就是说,int是32位(digits计数位但不是符号位). 尽管是无符号的,但是x被提升为32位带符号算术的溢出.signed int0xFFFF * 0xFFFF

演示一般问题:

// Compile on a recent version of clang and run it:
// clang++ -std=c++11 -O3 -Wall -fsanitize=undefined stdint16.cpp -o stdint16

#include <cinttypes>
#include <cstdint>
#include <cstdio>

int main()
{
     std::uint8_t a =  UINT8_MAX; …
Run Code Online (Sandbox Code Playgroud)

c++ portability multiplication undefined-behavior

30
推荐指数
3
解决办法
2945
查看次数

memcpy是一个简单的可复制类型的构造或作业?

假设您有一个类型对象T和一个适当对齐的内存缓冲区alignas(T) unsigned char[sizeof(T)].如果您使用std::memcpy从类型对象复制Tunsigned char数组,是否考虑复制构造或复制分配?

如果一个类型可以轻易复制而不是标准布局,那么可以想象一个类如下:

struct Meow
{
    int x;
protected: // different access-specifier means not standard-layout
    int y;
};
Run Code Online (Sandbox Code Playgroud)

可以像这样实现,因为编译器不会被强制使用标准布局:

struct Meow_internal
{
private:
    ptrdiff_t x_offset;
    ptrdiff_t y_offset;
    unsigned char buffer[sizeof(int) * 2 + ANY_CONSTANT];
};
Run Code Online (Sandbox Code Playgroud)

编译器可以存储xy喵的缓冲器内的任何部分buffer,甚至可能在随机内的偏移buffer,只要它们被适当地对准和不重叠.的偏移xy可即使编译愿与各施工随机变化.(如果编译器希望,x可以继续y使用,因为标准只要求相同访问说明符的成员按顺序排列,x并且y具有不同的访问说明符.)

这将符合可轻易复制的要求; a memcpy将复制隐藏的偏移字段,因此新副本将起作用.但有些事情是行不通的.例如,持有指向x跨越a 的指针memcpy会破坏:

Meow a;
a.x …
Run Code Online (Sandbox Code Playgroud)

c++ copy-constructor memcpy language-lawyer c++11

26
推荐指数
1
解决办法
1457
查看次数

将main声明为extern"C"是合法的C++吗?

作为一个低级程序员,我经常使用可执行文件的模块启动代码,所以我很清楚像"crt0"这样的代码是如何工作的.当编写C++代码,我通常声明mainextern "C"以匹配C启动代码会做打电话main.因此我通常使用此声明main(wmain如果专门针对Windows):

extern "C" int main(int argv, const char *const *argv)

extern "C" int __cdecl wmain(int argv, const wchar_t *const *argv)
Run Code Online (Sandbox Code Playgroud)

它是合法使用extern "C"main?此外,const char *const *argv的类型是合法的,而不是char *[]

c++ program-entry-point extern linkage

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

是否有用于检测iOS上的CPU功能的API?

我有一些具有多个实现的加密代码,根据运行的CPU的功能在运行时选择哪个实现.到目前为止移植这一点非常简单,Windows,Linux和Android都很容易.

但在iOS中它似乎并不容易.虽然x86 CPU具有cpuid检测功能的指令,但即使从用户模式也是如此,ARM等效功能具有特权.如果没有OS协作,就无法在ARM上检测CPU功能.

在Windows中,IsProcessorFeaturePresent用于检测ARM CPU功能.在Linux上,/proc/cpuinfo是要走的路.Android有一个cpufeatures库(/proc/cpuinfo仍然可以工作).Mac OS提供了sysctlbynamehw.optional.*.

但iOS呢?iOS内核hw.optional.*与Mac OS类似,但它在iOS 10中被锁定.(因此,我的问题不是这个问题的重复,因为情况已经改变了.)另外,获取这些列表似乎很难 - Apple的开源网站运行一个自动化流程,从公开发布的操作系统源中清除所有特定于ARM的代码,以使越狱者更加努力.

arm neon cpuid ios arm64

13
推荐指数
1
解决办法
759
查看次数

Visual C++是否考虑未定义的有符号整数溢出?

最近得到了很多关注,在C和C++中正式未定义有符号整数溢出.但是,给定的实现可以选择定义它; 在C++中,实现可以设置std::numeric_limits<signed T>::is_modulotrue指示已为该类型定义了有符号整数溢出,并且像无符号整数那样进行换行.

Visual C++设置std::numeric_limits<signed int>::is_modulotrue.这几乎不是一个可靠的指标,因为GCC多年来将其设置为真,并且未定义签名溢出.我从来没有遇到过一个案例,其中Visual C++的优化器已经做了任何事情,但是给签名整数提供了环绕行为 - 直到本周早些时候.

我发现了一个案例,其中优化器发出x86-64汇编代码,如果将exact的值INT_MAX传递给特定函数,则该代码执行不正确.我不知道它是否是一个错误,因为Visual C++似乎没有说明是否认为已经定义了有符号整数溢出.所以我想知道,它应该在Visual C++中定义吗?

编辑:我在阅读Visual C++ 2013 Update 2中一个不在Update 1中的令人讨厌的错误时发现了这一点,如果启用了优化,则以下循环会生成错误的机器代码:

void func (int *b, int n)
{
  for (int i = 0; i < n; i++)
    b[i * (n + 1)] = 1;
}
Run Code Online (Sandbox Code Playgroud)

更新2错误导致重复行生成其代码,就好像它一样b[i] = 1;,这显然是错误的.它变成了rep stosd.

真正有趣的是,在之前的版本Update 1 中存在奇怪之处.它生成的代码无法正确处理n完全相同的情况INT_MAX.具体来说,如果nINT_MAX,则乘法将表现为好像nlong long不是int- …

c++ visual-c++ c++11

12
推荐指数
1
解决办法
1062
查看次数

使用自签名证书验证Authenticode

如果我有一个不在机器的受信任根证书存储区中的自签名证书,如何在不将该证书添加到受信任的根存储区的情况下验证PE文件是否使用该证书进行了Authenticode签名?

C#是首选,但C++中的答案也很好.

StackOverflow上已经有很多类似的问题,但到目前为止还没有一个可以接受的答案.它必须是Authenticode,我无法将其添加到证书存储区.它也不能是购买的证书,因为它需要更长的有效时间(不论时间戳).

除了复制一大块Mono签名检查代码之外,我不知道Win32或.NET中的解决方案.

code-signing self-signed authenticode digital-signature

9
推荐指数
1
解决办法
285
查看次数

Clang有类似#pragma GCC目标吗?

我编写了一些代码,当它们在当前CPU上可用时使用AVX内在函数.在GCC和Clang中,与Visual C++不同,为了使用内在函数,必须在命令行上启用它们.

GCC和Clang的问题在于,当您启用这些选项时,您可以让编译器自由统治,以便在源文件中的任何位置使用这些指令.当你有包含内联函数或模板函数的头文件时,这是非常糟糕的,因为编译器将使用AVX指令生成这些函数.

链接时,将丢弃重复的函数.但是,由于某些源文件是使用编译而某些源文件-mavx未编译的,因此内联/模板函数的各种编译将有所不同.如果你运气不好,链接器将随机选择具有AVX指令的版本,导致程序在没有AVX的系统上运行时崩溃.

GCC解决了这个问题#pragma GCC target.您可以关闭头文件的特殊说明,生成的代码不会使用AVX:

#pragma GCC push_options
#pragma GCC target("no-avx")

#include "MyHeader.h"

#pragma GCC pop_options
Run Code Online (Sandbox Code Playgroud)

Clang有这样的东西吗?它似乎忽略了这些选项并且无论如何都会生成AVX代码.

pragma clang intrinsics avx

9
推荐指数
2
解决办法
718
查看次数

如何从 Android NDK .so 文件中去除符号?

如何从 Android.so原生代码库中剥离符号?

我有一个.so在十六进制编辑器中清晰可见的数千个符号。IDA Pro 根据可执行文件中的符号自动使用适当的符号进行反汇编。

但是,如果我要求nm转储符号表,它会说没有。 strip并且objcopy也没有效果。

C:\AndroidProject.apk\lib\armeabi-v7a>arm-linux-androideabi-strings.exe libMeow.so | findstr _ZN11SecretClass14SecretFunctionERKS_
_ZN11SecretClass14SecretFunctionERKS_

C:\AndroidProject.apk\lib\armeabi-v7a>arm-linux-androideabi-nm.exe libMeow.so
arm-linux-androideabi-nm.exe: libMeow.so: no symbols

C:\AndroidProject.apk\lib\armeabi-v7a>copy /y libMeow.so libMeow-test.so
        1 file(s) copied.

C:\AndroidProject.apk\lib\armeabi-v7a>sha1sum libMeow.so libMeow-test.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow-test.so

C:\AndroidProject.apk\lib\armeabi-v7a>arm-linux-androideabi-strip.exe libMeow-test.so

C:\AndroidProject.apk\lib\armeabi-v7a>sha1sum libMeow.so libMeow-test.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow-test.so

C:\AndroidProject.apk\lib\armeabi-v7a>arm-linux-androideabi-strip.exe -g libMeow-test.so

C:\AndroidProject.apk\lib\armeabi-v7a>sha1sum libMeow.so libMeow-test.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow.so
0a36701ba44b4cfb31e6f6506349493d5466cd70 *libMeow-test.so
Run Code Online (Sandbox Code Playgroud)

名称已更改以保护有罪的人。

android debug-symbols android-ndk

7
推荐指数
1
解决办法
7450
查看次数

确定C++类是否具有私有析构函数

假设我有以下代码:

class Example
{
#ifndef PRIVATE_DESTRUCTOR
public:
#endif
    ~Example() { }
public:
    friend class Friend;
};

class Friend
{
public:
    void Member();
};

void Friend::Member()
{
    std::printf("Example's destructor is %s.\n",
        IsDestructorPrivate<Example>::value ? "private" : "public");
}
Run Code Online (Sandbox Code Playgroud)

是否有可能实现IsDestructorPrivate上面的模板来确定一个类的析构函数是否private还是protected

在我正在使用的情况下,我需要使用它的唯一时间IsDestructorPrivate是在有权访问这种私有析构函数的地方(如果存在的话).它不一定存在.IsDestructorPrivate允许是宏而不是模板(或者是解析为模板的宏).C++ 11很好.

c++ destructor private c++11

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

如何检索C99可变参数宏的最后一个参数?

Visual Studio的失败static_assert的错误消息完全由一个错误代码和static_assert的第二个参数组成,没有任何其他消息表明它是静态断言失败.我想制作一个宏来解决这个问题.例如,作为第一次尝试:

#define STATIC_ASSERT(x) static_assert(x, "static assertion failed: " #x)
Run Code Online (Sandbox Code Playgroud)

您遇到的第一个问题是C预处理器不理解< >为封闭分隔符,这会导致模板出现语法错误.以下内容变为非法:

template <typename T, typename U>
auto SafeMultiply(T x, U y) -> decltype(x * y)
{
    STATIC_ASSERT(std::is_same<T, U>::value);
    STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
    if (x > (std::numeric_limits<decltype(x * y)>::max)())
        throw std::overflow_error("multiplication overflow");
    return x * y;
}
Run Code Online (Sandbox Code Playgroud)

这是非法的,因为第一个中的T和U之间的逗号STATIC_ASSERT被解释为分隔两个宏参数,而不是模板参数.C预处理器抛出错误,因为STATIC_ASSERT宏只接受一个参数.

这个问题的两个主要解决方案是使用双括号,最近使用可变参数宏:

// Invoke the macro this way...
STATIC_ASSERT((std::is_same<T, U>::value));
// ...or define it this way:
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), \
    "static assertion failed: " #__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

后一种解决方案更好,只需要更改宏定义.(__VA_ARGS__新定义中的额外括号是为了在某些更奇怪的情况下保持正确的操作顺序.在这个特定的宏中可能无关紧要,但在宏定义中将括号括在宏的参数周围是个好习惯. )

现在,如果我想更改我的 …

c c++ c99 c-preprocessor

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