Насколько скорость уменьшается с размером вызываемого аргумента?(C / C ++) - PullRequest
0 голосов
/ 23 марта 2012

Я должен принять решение, которое будет очень важно для дальнейшей разработки моего приложения, поэтому оно должно быть идеальным.

Фактический вопрос:

ДляДля простоты лучше иметь дополнительные 20 пустых байтов, но это кажется крайне неэффективным.Насколько сильно затрагивается моя программа, когда я передаю 50-байтную структуру в функцию?= P

И почему я спрашиваю:

Я запускаю 64 бита.Это означает 8 байт на переменную.В настоящее время stuff_s имеет размер 3*8=24 байт.

  • Просто добавьте еще три / четыре переменные, но увеличьте размер структуры и вызовите функцию замедления.сложные, но безопасные дополнительные байты (и пространство ОЗУ).

Я буду использовать эти stuff_s 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 ]

2 голосов
/ 23 марта 2012

Используйте ссылки.

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, а также включить передачу по ссылке.Имейте в виду, что это концептуально: он будет компилироваться, но он не очень полезен.

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;
  }
}
0 голосов
/ 23 марта 2012

Во-первых, если вы добавите некоторые методы доступа в свою структуру, вы можете смело изменять реализацию структуры завтра, не затрагивая любой другой код.

Например,

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 и подумать об оптимизации, когда ваша программа на самом деле слишком медленная

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...