Visual C ++ __forceinline奇怪的行为 [英] Visual C++ __forceinline strange behavior

查看:71
本文介绍了Visual C ++ __forceinline奇怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图强制Visual C ++编译器内联特定功能.我知道inline__forceinline只是一个建议.根据 MSDN ,如果编译器无法内联使用关键字,然后它会生成警告:

I'm trying to force visual c++ compiler to inline a particular function. I know that inline or __forceinline is just a suggestion. According MSDN, if compiler cannot inline function which is marked using __forceinline keyword then it generates warning:

如果编译器无法内联用__forceinline声明的函数, 它会产生1级警告.

If the compiler cannot inline a function declared with __forceinline, it generates a level 1 warning.

但是我没有得到这样的警告.当我调试我的应用程序时,我看到在反汇编窗口中有一个call <inlined function address>,即我的函数没有被内联.那么,如何检查我的函数是否已内联?这是否意味着如果未生成警告,则内联函数并将问题放在其他位置?

But I have not got such warning. And when I debug my application I see that there is a call <inlined function address> in Disassembly window i.e. my function was not inlined. So how can I check is my function was inlined or not? Does it mean that if no warning was generated then function was inlined and the problem somewhere in other place?

这是我的功能:

__forceinline SecByteBlock aes_generate_iv(size_t blockSize)
{
    const int seedSize = 32;
    SecByteBlock rngSeed(seedSize);
    OS_GenerateRandomBlock(false, rngSeed, rngSeed.size());

    RandomPool rngp;
    rngp.IncorporateEntropy(rngSeed, rngSeed.size());

    SecByteBlock aesIV(blockSize);
    rngp.GenerateBlock(aesIV, aesIV.size());

    return aesIV;
}

在某些情况下,VC ++无法内联功能(来自 MSDN ):

Here is circumstances then VC++ cannot inline function (from MSDN):

  • 该函数或其调用者使用/Ob0(调试版本的默认选项)进行编译.
  • 函数和调用者使用不同类型的异常处理(一种是C ++异常处理,另一种是结构化异常处理).
  • 该函数具有可变的参数列表.
  • 该函数使用内联汇编,除非使用/Og,/Ox,/O1或/O2进行编译.
  • 该函数是递归的,不附带#pragma inline_recursion(on).使用编译指示时,递归函数将内联到默认深度为16的调用中.要减少内联深度,请使用inline_depth编译指示.
  • 该函数是虚拟的,实际上是被调用的.可以内联对虚拟函数的直接调用.
  • 程序获取函数的地址,并通过指向函数的指针进行调用.可以内联直接调用已采用其地址的函数.
  • 该函数还标有裸露的__declspec修饰符.

推荐答案

同一警告有2个版本:

https://msdn.microsoft. com/en-us/library/aa734011(v = vs.60).aspx

编译器警告(等级1)C4714
Visual Studio 6.0
'function':标记为__forceinline的函数未内联
Compiler Warning (level 1) C4714
Visual Studio 6.0
'function' : function marked as __forceinline not inlined

https://msdn.microsoft.com/en-us/library /a98sb923.aspx

编译器警告(等级4)C4714
Visual Studio 2015
标记为__forceinline的函数'function'未内联
Compiler Warning (level 4) C4714
Visual Studio 2015
function 'function' marked as __forceinline not inlined

因此,要启用警告,例如,在Visual Studio 2015中,默认情况下必须使用4级(/W4)而不是3级(/W3).

So, to enable the warning, for example, in the Visual Studio 2015 you have to use Level 4 (/W4) instead of Level 3 (/W3) as by default.

以下有关如何消除此类编译器行为的建议. 我已经在MSVC2015中解决了这些情况:

Below some advices for how to eliminate such compiler behaviour. I've resolved these set of cases in the MSVC2015:

  1. 递归调用
  2. SomeType SomeType::operator++(int)/SomeType SomeType::operator--(int)
  3. std::string在__forceinline函数中按值返回
  1. Recursion calls
  2. SomeType SomeType::operator++(int)/SomeType SomeType::operator--(int)
  3. std::string returned by value in __forceinline functions

1.递归调用

template <typename T>
__forceinline T int_log2_floor(T v)
{
    ASSERT_GT(v, T(0));

    if (1 >= v) return 0;

    return T((v >= 2 ? int_log2_floor(v / 2) : 0) + 1); // Warning C4714
}

这里的解决方案之一就是展开递归:

One of solution here is just to unroll the recursion:

template <typename T>
__forceinline T int_log2_floor(T v)
{
    ASSERT_GT(v, T(0));

    if (1 >= v) return 0;

    T ret = 0;
    T i = v;

    do {
        ++ret;
        i /= 2;
    } while (i >= 2);

    return ret;
}

2. `SomeType SomeType :: operator ++(int)`/`SomeType SomeType :: operator-(int)`

class SomeType
{
    __forceinline SomeType operator++(int) // Warning C4714
    {
        const auto it = *this;
        m_it++;
        return it;
    }

    //...
    iterator m_it
};

这个对我有用:

class SomeType;

SomeType operator++(SomeType & r, int);

class SomeType
{
    friend SomeType operator++(SomeType & r, int);

    //...
    iterator m_it
};

__forceinline SomeType operator++(SomeType & r, int)
{
    const auto it = r;
    r.m_it++;
    return it;

    // You still can write here `const auto it = *this; m_it++; return it`,
    // but i hell don't know why this works.
}

3. __forceinline函数中按值返回的`std :: string`

这真的很奇怪,但是似乎之间存在某种干扰 在inline -ed函数之间的__forceinline -ed函数,因为std::string基本上使用第二个-inline.

3. `std::string` returned by value in __forceinline functions

This one is really strange, but seems there is some kind of interference between __forceinline-ed functions between inline-ed functions because std::string basically uses second one - inline.

template<typename T>
__forceinline std::string int_to_bin(T i, bool first_bit_is_lowest_bit = false) // Warning C4714
{
    std::bitset<sizeof(T) * CHAR_BIT> bs(i);
    if (!first_bit_is_lowest_bit) {
        return bs.to_string();
    }

    const std::string bs_str = bs.to_string();
    return std::string(bs_str.rbegin(), bs_str.rend());
}

由于警告是由按值返回类型触发的,因此解决方案是改为通过参数返回,并按inline内联:

Because the warning has triggered by return-by-value type, the solution here is to return through the parameter instead and inline by inline:

template<typename T>
__forceinline void int_to_bin_forceinline(std::string & ret, T i, bool first_bit_is_lowest_bit = false)
{
    std::bitset<sizeof(T) * CHAR_BIT> bs(i);
    if (!first_bit_is_lowest_bit) {
        ret = bs.to_string();
        return;
    }

    const std::string bs_str = bs.to_string();
    ret = std::string(bs_str.rbegin(), bs_str.rend());
    return;
}

template<typename T>
inline std::string int_to_bin(T i, bool first_bit_is_lowest_bit = false)
{
    std::string res;
    int_to_bin_forceinline(res, i, first_bit_is_lowest_bit);
    return res;
}

不用说,可以通过使用inline关键字而不是__forceinline来解决所有3个版本.

Needless to say all 3 versions can be workarounded by the inline keyword usage instead of the __forceinline.

这篇关于Visual C ++ __forceinline奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆