Краткий способ инициализации блока памяти магическими числами - PullRequest
4 голосов
/ 28 сентября 2011

Несколько примеров того, что я имею в виду:

typedef struct SOME_STRUCT {
  unsigned int x1;
  unsigned int x2;
  unsigned int x3;
  unsigned int x4;

  // What I expected would work, but doesn't; the 2nd parameter gets
  // turned into an 8-bit quantity at some point within memset
  SOME_STRUCT() { memset( this, 0xFEEDFACE, sizeof( *this ) ); }

  // Something that worked, but seems hokey/hackish
  SOME_STRUCT() {
    unsigned int *me = (unsigned int *)this;
    for( int ii = 0; ii < sizeof(*this)/sizeof(*me); ++ii ) {
      me[ii] = 0xFEEDFACE;
    }
  }

  // The far-more-verbose-but-C++-way-of-doing-it
  // This works, but doesn't lend itself very well
  // to being a drop-in way to pull this off on
  // any struct.
  SOME_STRUCT() :  x1( 0xFEEDFACE )
                 , x2( 0XFEEDFACE )
                 , x3( 0XFEEDFACE )
                 , x4( 0XFEEDFACE ) {}

  // This would work, but I figured there would be a standard
  // function that would alleviate the need to do it myself
  SOME_STRUCT() { my_memset( this, 0xFEEDFACE, sizeof(*this) ); }
}

Я не могу использовать valgrind здесь, и мои параметры ограничены, поскольку различные библиотеки отладки, к которым у меня есть доступ, - этопочему я делаю это сам для этого одноразового дела.

Ответы [ 7 ]

4 голосов
/ 28 сентября 2011

Вот частичный пример безопасного использования std::generate():

#include <algorithm>

struct Wizard {
    size_t i;
    static unsigned char magic[4];
    Wizard() : i(0) {}
    unsigned char operator()() {
        size_t j = i++;
        i %= sizeof(magic); // Not strictly necessary due to wrapping.
        return magic[j];
    }
};

unsigned char Wizard::magic[4] = {0xDE,0xAD,0xBE,0xEF};

std::generate(reinterpret_cast<unsigned char*>(this),
              reinterpret_cast<unsigned char*>(this) + sizeof(*this),
              Wizard());

(Конечно, порядковый номер может быть или не быть правильным, в зависимости от того, как вы выглядите и что вы ожидаете увидеть, когда вы делаете!)

2 голосов
/ 28 сентября 2011

Замечание, не высказанное другими:По иронии судьбы, добавление инициализации в конструктор делает его не-pod.Поэтому я предлагаю автономную функцию, которая статически проверяет POD-ness (в примере используется c ++ 0x type_traits, но вы также можете использовать Boost)

#include <iostream>
#include <type_traits>

template <typename T>
    typename std::enable_if<std::is_pod<T>::value>::type* FeedFace(T& v)
{
    static const unsigned char MAGIC[] = { 0xFE, 0xED, 0xFA, 0xCE };
    unsigned char *me = reinterpret_cast<unsigned char *>(&v);
    for( size_t ii = 0; ii < sizeof(T)/sizeof(unsigned char); ++ii ) 
        me[ii] = MAGIC[ii % sizeof(MAGIC)/sizeof(unsigned char)];
}

struct Pod { char data[37]; };
struct NonPod : Pod { virtual ~NonPod() { } };

int main()
{
    Pod pod;
    FeedFace(pod);

    NonPod nonpod;
    // FeedFace(nonpod); // fails to compile (no matching function call)

    return 0;
}
2 голосов
/ 28 сентября 2011

Я бы объявил этот конструктор:

SOME_STRUCT( unsigned int magic) : x1 (magic), x2 (magic), x3 (magic), x4 (magic) {}

Это очень похоже на ваш третий вариант и кажется естественным способом сделать это на C ++.

1 голос
/ 28 сентября 2011

Вы можете reinterpret_cast this как char*, а затем использовать std::generate с предикатом, который вращается через значения, которые вас интересуют. Если у меня будет время, я постараюсь набросать код.

Также вы рассматривали, например, проверку памяти malloc библиотекой LD_PRELOAD?

1 голос
/ 28 сентября 2011

Я предполагаю, что это допускает неприятные хакерские вещи, например:

#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
int main(void)
{
    struct SOME_STRUCT {
        unsigned int x1;
        unsigned int x2;
        unsigned int x3;
        unsigned int x4;
    } foo;
    fill(reinterpret_cast<unsigned int *>(&foo),
         reinterpret_cast<unsigned int *>(&foo) + sizeof(foo) / sizeof(unsigned int),
         (unsigned int)0xDEADBEEF);
    cout << foo.x1 << endl;
    cout << foo.x2 << endl;
    cout << foo.x3 << endl;
    cout << foo.x4 << endl;
    return (0);
}

В основном злоупотребление std :: fill () с приведением указателей.

0 голосов
/ 28 сентября 2011

Даже если ваша попытка memset() сработала, она делает предположение о структуре упаковки и, следовательно, не гарантирует ее правильности. Не существует программного способа перебора членов структуры и назначения их в C или C ++. Поэтому вам нужно быть довольным назначением участников по отдельности. Сказав это, если вы чувствуете, что вам удобно с макетом памяти структуры и вам не нужно беспокоиться о переносимом коде, вы можете легко инициализировать его с помощью цикла for.

unsigned int i, *ar = (unsigned int *)&my_struct;
for (i = 0; i < sizeof(my_struct) / sizeof(unsigned int); i++) {
  ar[i] = 0xdeadbeef;
}
0 голосов
/ 28 сентября 2011

Вот еще один хакерский метод.

SOME_STRUCT() {
    x1 = 0xFEEDFACE;
    memmove(&(this->x2), this, sizeof(*this)-sizeof(x1));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...