Подтвердить что ты не робот

C struct hack на работе

Это как можно использовать "лишнюю" память, выделенную при использовании C struct hack?

Вопросы:

У меня есть реализация C struct hack ниже. Мой вопрос в том, как я могу использовать "лишнюю" память, которую я выделил с помощью взлома. Может кто-нибудь, пожалуйста, дайте мне пример использования этой дополнительной памяти?

#include<stdio.h>
#include<stdlib.h>

int main()
{

    struct mystruct {

        int len;
        char chararray[1];

    };

    struct mystruct *ptr = malloc(sizeof(struct mystruct) + 10 - 1);
    ptr->len=10;


    ptr->chararray[0] = 'a';
    ptr->chararray[1] = 'b';
    ptr->chararray[2] = 'c';
    ptr->chararray[3] = 'd';
    ptr->chararray[4] = 'e';
    ptr->chararray[5] = 'f';
    ptr->chararray[6] = 'g';
    ptr->chararray[7] = 'h';
    ptr->chararray[8] = 'i';
    ptr->chararray[9] = 'j';


}
4b9b3361

Ответ 1

Да, это (и был) стандартный способ в C для создания и обработки размера struct с переменным размером.

Этот пример немного подробный. Большинство программистов справятся с этим более ловко:

struct mystruct {
        int len;
        char chararray[1];  // some compilers would allow [0] here
    };
    char *msg = "abcdefghi";
    int n = strlen (msg);

    struct mystruct *ptr = malloc(sizeof(struct mystruct) + n + 1);

    ptr->len = n;
    strcpy (ptr->chararray, msg);
}

Ответ 2

С тех пор, как я прочитал эту статью (http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx), мне понравилось использовать хакерство структуры так:

  #include<stdio.h>
  #include<stdlib.h>

  int main()
  {

      struct mystruct {

          int len;
          char chararray[1];
      };

      int number_of_elements = 10;

      struct mystruct *ptr = malloc(offsetof(struct mystruct, chararray[number_of_elements]));
      ptr->len = number_of_elements;

      for (i = 0; i < number_of_elements; ++i) {
        ptr->chararray[i] = 'a' + i;
      }

  }

Я считаю, что не нужно помнить, что нужно вычитать (или добавить или что-то другое). У этого также есть бонус работать в ситуациях, когда 0 используется в определении массива, который не все компиляторы поддерживают, но некоторые делают. Если распределение основано на offsetof(), вам не нужно беспокоиться о том, что возможные детали делают вашу математику неправильной.

Он также работает без изменений, так как структура является членом гибкого массива C99.

Ответ 3

Я бы посоветовал не учитывать это из-за возможных проблем выравнивания:

struct my_struct
{
    char *arr_space;
    unsigned int len;
}

struct my_struct *ptr = malloc(sizeof(struct my_struct) + 10);
ptr->arr_space = ptr + 1;
ptr->len = 10;

Это даст вам местность, а также безопасность:) и избежать странных проблем с выравниванием.

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

В исходном примере, если вы добавляете элемент с байтом или без слова (byte, char, short), тогда компилятор может расширить размер структуры, но, насколько ваш указатель, вы читаете память напрямую после окончания структуры (не выравнивается). Это означает, что если у вас есть массив выровненного типа, такой как int, каждый доступ будет иметь производительность, получаемую от процессоров, которые получают хиты от чтения неизмененной памяти.

struct
{
    byte_size data;
    char *var_len;
    some_align added by compiler;
}

В исходном случае вы будете читать из области some_align, которая является только наполнителем, но в моем случае вы будете читать после выровненной дополнительной памяти (которая отнимает некоторое пространство, но обычно это нормально).

Другим преимуществом этого является то, что можно получить больше местностей из распределений, выделив все пространство для членов переменной длины из struct в одном распределении, а не выделяя их отдельно (избегает множественных накладных расходов на распределение и дает вам некоторые кеш, а не перехватывать всю память).

Ответ 4

Это "правильно", но для этого вам нужна хорошая причина сделать это более разумным решением. Более часто, возможно, вы использовали бы этот метод для "наложения" некоторого существующего массива, чтобы наложить на него какую-то структуру заголовков.

Обратите внимание, что GCC по расширению позволяет элемент массива нулевой длины именно для этой цели, тогда как ISO C99 "узаконивает" практику, разрешая члену с пустыми скобками (только как последний элемент).

Обратите внимание, что есть некоторые семантические проблемы - размер структуры не будет, конечно, учитывать "гибкий" размер конечного элемента, а передача структуры "по значению" будет проходить только через заголовок и первый элемент (или ни один элемент используя расширение GCC или элемент гибкой матрицы C99). Точно так же прямое назначение структуры не будет копировать все данные.