首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++函数中的默认参数化是否将默认值推送到堆栈上?

C++函数中的默认参数化是否将默认值推送到堆栈上?
EN

Stack Overflow用户
提问于 2013-11-28 02:47:55
回答 2查看 225关注 0票数 0

如果一个函数有20个参数(指针)(示例中使用的4个),所有参数的默认值都指向NULL,这是否意味着每次对该函数的调用都会在运行时推堆栈一个空值?

这样的函数示例可能如下所示:

代码语言:javascript
复制
function test(val1=NULL, val2=NULL, .... val20=NULL)

我要求这样做是为了最大限度地提高速度,并在函数调用期间减少#循环。

测试用例(这里还有一些额外的东西)

代码语言:javascript
复制
// ArgsListTest.cpp
// @author Mathew Kurian

#include "stdafx.h"
#include <iostream>
#include <time.h>

using namespace std;

// Look at the difference in psuedo-assembly code
// My knowledge in compiler is little, but I can see that
// that there are unncessary cycles being wasted for this part.

// **** With array (this example) *****
// LOAD         Reg, memAddressOfArray
// WRITETOMEM   Reg, ptrToVar1
// INCREMENT    sp
// WRITETOMEM   Reg, ptrToVar2
// DECREMENT    sp
// PUSH         ptrToArray
// JUMP         test

//  ***** IDEALLY SUPPOSED TO LIKE THIS *****
// PUSH        ptrToVar2
// PUSH        ptrToVar1
// JUMP        test

class Base
{
public:
    virtual int test(void* arguments[])
    {
        cout << "Base function being called. VTable lookup ignored since there is no virtual." << endl;
        cout << *static_cast<int*>(arguments[0]) << endl;   // Parameter 1 (Thinks there is only 1 parameter!)

        int x = 5;      x += 1; // Random math to prevent optimizations. (I hope)
        return x;
    }
};

class Derived : public Base
{
public:
    virtual int test(void* arguments[])
    {
        // cout << "Derived function being called. VTable lookup during runtime. Slight overhead here!" << endl;

        // cout << *static_cast<string*>(arguments[0]) << endl; // Parameter 1
        // cout << *static_cast<int*>(arguments[1]) << endl;   // Parameter 2

        int x = 5;      x += 1;
        return x;
    }
};

class Base2
{
public:
    virtual int test(void* arg1 = NULL, void* arg2 = NULL, void* arg3 = NULL, void* arg4 = NULL)
    {
        // cout << "Base2 function being called. VTable lookup ignored since there is no virtual." << endl;

        // cout << *static_cast<string*>(arg1) << endl; // Parameter 1
        // cout << *static_cast<int*>(arg2) << endl;   // Parameter 2
        int x = 5;      x += 1;
        return x;
    }

    virtual int test2()
    {
        int x = 5;      x += 1;
        return x;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Base * base = new Derived;
    Base2 * base2 = new Base2;

    int r = 0;
    string * str = new string("sunny");
    int * vale = new int(20);
    int iterations = 1000000000;

    //================================================================================

    printf("Using No-Parameters [%d iterations]\n", iterations);

    clock_t tStart = clock();

    for (int x = 0; x < iterations; x++)
    {
        r = base2->test2();
    }

    printf("Time taken: %.9fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);

    //================================================================================

    printf("Using Array [%d iterations]\n", iterations);

    tStart = clock();

    for (int x = 0; x < iterations; x++)
    {
        void * arguments[] = { str, vale };
        r = base->test(arguments);
    }

    printf("Time taken: %.9fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);

    //================================================================================

    printf("Using Default-Parameters [%d iterations]\n", iterations);

    tStart = clock();

    for (int x = 0; x < iterations; x++)
    {
        r = base2->test(str, vale);
    }

    printf("Time taken: %.9fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);

    //================================================================================

    // cout << "NOTE: Derived class has no extra methods although the parameter counts are different.\n      Parent class doesn't even realize parameter 1 exists!" << endl;

    std::getchar();

    return 0;
}

输出(这不符合逻辑)

为什么第一次测试比第二次测试慢?以及如何创建数组实际上比只创建PUSH NULL更快

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-28 05:18:44

也许虚拟方法正在影响您的结果。我将您的方法复制到全局范围,这演示了不同的性能顺序。

代码语言:javascript
复制
Using No-Parameters [1000000000 iterations]
Time taken: 24.831000000s
Using Array [1000000000 iterations]
Time taken: 24.730000000s
Using Default-Parameters [1000000000 iterations]
Time taken: 25.241000000s
Using No-Parameters [1000000000 iterations] on int testA()
Time taken: 21.664000000s
Using Array [1000000000 iterations] on int testB(void* arguments[])
Time taken: 22.384000000s
Using Default-Parameters [1000000000 iterations] int testC(void* arg1 = NULL, ...)
Time taken: 22.329000000s

编辑:

与testB中的数组赋值相同的测试移出了for循环的范围:

代码语言:javascript
复制
Using No-Parameters [1000000000 iterations]
Time taken: 24.713000000s
Using Array [1000000000 iterations]
Time taken: 24.686000000s
Using Default-Parameters [1000000000 iterations]
Time taken: 25.225000000s
Using No-Parameters [1000000000 iterations] on int testA()
Time taken: 21.653000000s
Using Array [1000000000 iterations] on int testB(void* arguments[])
Time taken: 21.896000000s
Using Default-Parameters [1000000000 iterations] int testC(void* arg1 = NULL, ...)
Time taken: 22.353000000s
票数 2
EN

Stack Overflow用户

发布于 2013-11-28 17:42:37

也许吧。另一个简单的解决方案是有多个入口点:

代码语言:javascript
复制
  # Pseudocode
  PUSH nullptr # Default argument 20
  PUSH nullptr # Default argument 19
  PUSH nullptr # Default argument 18
  ...
  ENTRYPOINT(test)

如果有N个默认参数,则跳到常规入口点前面的地址N指令。好处:推送这些默认参数的代码现在可以在调用方之间共享。不过,需要一点链接器的机智。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20256831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档