gcc对象按值或按地址传递

时间:2017-03-16 20:29:20

标签: c++ linux gcc parameter-passing calling-convention

我们有这个简单的课程:

class MyStr
{
public:
    MyStr() { }
    wchar_t* pStr;
};

以及使用它的代码:

MyStr ms1, ms2;
ms1.pStr = L"MyStr!"; 
ms2.pStr = L"MyStr2!";

wchar_t buffer[100];
swprintf(buffer, 100, L"%ls - %ls", ms1, ms2);

将ms1和ms2压入堆栈的程序集如下所示:

FF B5 24 FE FF FF    push DWORD PTR [ebp-0x1dc] 
FF B5 20 FE FF FF    push DWORD PTR [ebp-0x1e0] 

它实际上是将MyStr的值/内容(在本例中只是pStr)推送到堆栈上。

如果我们将MyStr更改为只添加一个简单的析构函数:

class MyStr
{
public:
    MyStr() { }
    ~MyStr() { }
    wchar_t* pStr;
};

现在传递ms1和ms2的地址,而不是它们的值/内容。

8D 85 24 FE FF FF    lea eax,[ebp-0x1dc] 
50                   push eax 
8D 85 20 FE FF FF    lea eax,[ebp-0x1e0] 
50                   push eax

Windows上的Visual Studio以两种方式提供相同的结果(总是传递值/内容),但Linux上的gcc给出了这两种不同的结果。

  1. 为什么?
  2. 我们可以做些什么来保持析构函数,但是通过值而不是引用/地址传递?
  3. 我们做不到的事情就是更改swprintf行 - 有成千上万行,我们正试图避免更改它们。

1 个答案:

答案 0 :(得分:2)

你可以诉诸MACRO

// Forward call to your method
#define swprintf(...) my_swprintf(__VA_ARGS__)

// Your class
class MyStr
{
public:
    MyStr() { }
    ~MyStr() { }
    const wchar_t* pStr;
};


// helper function to "fix" parameters
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value || std::is_pointer<T>::value, T>
normalize(T t) { return t; } // Default one which does nothing

// Fix for your class to return its member.
const wchar_t* normalize(const MyStr& t) { return t.pStr; }

// Your function which (re-)forward to real swprintf with fixed parameter
// Extra parent do avoid macro substitution
template <typename ... Ts>
auto my_swprintf(wchar_t* buffer, const wchar_t* format, const Ts&... args)
{
    return (swprintf)(buffer, format, normalize(args)...);
}