调用参数大小,速度会降低多少? (C / C ++)

时间:2012-03-22 21:11:12

标签: c struct stack

我必须做出一个在我的应用程序的未来开发中非常重要的决定,所以它必须是完美的。

实际问题:

为了方便起见,最好还有20个空字节,但这似乎效率极低。当我将50字节的大结构传递给函数时,我的程序受影响了多远? = P

为什么我要问:

我跑64位。这意味着每个变量8个字节 目前stuff_s的字节数为3*8=24

  • 只需添加三/四个变量,但膨胀结构大小并减慢函数调用。
  • 或选择某些非常复杂但安全的附加字节(和RAM空间)。

我将使用这些stuff_s来包含树中任何类型的数据对象,它们可以处理对象或模块(这是特定的,忽略模块)。数据对象的大小可能不同......它们甚至可能比通常的结构使用几千兆字节。现在我不希望每个该死的结构都携带额外的50个字节。如果那可能只有一个字节,或者不超过8 ...... =(

我有一个结构:

//
// stuff reference (either module or object)
//
struct stuff_s
{
    char s; // stuff: 'm' || 'o'
    union {
        struct {
            mfunc_t *fs;
            ppackage (*knockf)(ppackage p);
        } m;
        struct {
            void *h;
            size_t s;
            // HERE should the additional variables go.
        } o;
    };
};

2 个答案:

答案 0 :(得分:2)

使用参考。

C ++:

void foo(stuff_s &what)
{
  what.o.s = 4;
}

int main()
{
  stuff_s SetToFour;
  foo(SetToFour);
}

C:

void foo(stuff_s *what)
{
  if (what == NULL) return;
  what->o.s = 4;
}

int main(int argc, char *argv[])
{
  stuff_s SetToFour;
  foo(&SetToFour);

  return 0; /* Because it's main in a strict C compiler. Ignore this. */
}

关于程序的设计,如果你的数据确实是真的不可知,我建议使用void *指针和对象类型标记,或者从基类派生一个类。

C ++:

class base {
  public:
    int a;
    virtual void do_whatever();
    virtual int get_type() = 0; // Grab our type ID
};

class derived : public base {
  public:
    int b;
    float c;
    char *d;
    virtual void do_whatever() { c = 4.0F; }
    virtual int get_type() { return 1; }
};

struct stuff_s {
//    ...in o
  base *futs;
}

// Later on...
stuff_s foo;
switch (foo.o.futs->get_type()) {
  case 0: // Base class
    break;
  case 1: // Class type 'derived'
    derived *a = dynamic_cast<derived *>(foo.o.futs); // Dynamic cast lets us take a pointer to a base type and make it into a pointer to a derived type. Using our tag ID that we get from the virtual function, we can determine exactly which type to do.
    a->b = 4;
    break;
}
// This is roughly the same amount of code as the C version would use

如果你真的想要我提供一个C例子,但这已经过长了

编辑:我在下面看到它必须与C兼容。因此,我将扩展为包含最后一个代码的C等价物,并且还包括通过引用传递。请记住,这是概念性的:它会编译,但它不是非常有用。

C:

/* This is a generic object. It has a type ID and a pointer, that is all that is needed. It can hold anything. */
struct generic_holder {
  int type;
  void *ptr;
};

/* This is an example struct it may point to. */
struct holder_one {
  int a;
  int b;
  float c;
  char *d;
  int change_this;
};

/* This is another example struct. */
struct holder_two {
  char best[50];
  char worst[50];
  int change_this;
};

struct stuff_s {
/*    ...in .o */
  generic_holder data;
};

/* Forward-declaration */
void set_to_four(stuff_s *foo);

/* Later on... */
int main(int argc, char* argv[])
{
  stuff_s foo;
  holder_two test_struct = { "C++", "Lisp", 0 };  // Best, worst. Haha.

  foo.o.data.ptr = (void *)&test_struct; /* This makes it into a "generic pointer" by casting it to void */

  foo.o.data.type = 2; /* = 2 because we are using holder_two */

  /* We're going to use our function to set data in a generic object, passing by reference. This would work equally well on something of type holder_one, and can be expanded for data types you haven't thought of. */
  set_to_four(&foo);

  return 0;
}

/* This function will take a generic object and set the 'change_this' variable to 4 */
void set_to_four(stuff_s *foo)
{
  holder_one *ptr1;
  holder_two *ptr2;

  if (foo == NULL) return;            /* Obsessively check for invalid pointers */
  assert(foo.o.data.ptr != NULL);     /* Some people prefer to do checks only in debug, for speed. This does the same thing but only if debug is on. And it stops the program when it gets there if there is an error. It evaluates to nothing if it's a release build. */

  switch(foo.o.data.type) {
    case 1:
      ptr1 = (holder_one *)foo.o.data.ptr;
      ptr1->change_this = 4;
      break;
    case 2:
      ptr2 = (holder_two *)foo.o.data.ptr;
      ptr2->change_this = 4;
      break;
    default:
      break;
  }
}

答案 1 :(得分:0)

首先,如果在结构中放置一些访问器,则可以在不影响任何其他代码的情况下安全地更改结构的实现。

例如,

struct MyStruct
{
    int getVal() {return val;}
    int val;
}

关于问题的另一半,我担心没有直截了当的回答。你应该尝试两种方法并亲自测试一下。

我注意到你认为拥有额外的字节“更容易”如果你在谈论打字,这不是真的,因为你可以使用位域,即

struct MyStruct
{
    unsigned val1 : 10; // val1 is 10 bits long
    unsigned val2 : 3;  // val2 is 3 bits big
};

// access values
MyStruct s;
s.val1 = ...;

此外,如果将const ref传递给它而不是通过值,函数调用将不会被传入的大小“减慢”。那就是:

void foo( const MyStruct & myStruct)
{ 
//eg: myStruct.val1 = 10; // your code here 
}

至于你的新“实际问题”

它不会影响速度,除非它在某个内环中。经验法则是通过const ref,并在程序实际上太慢时考虑优化