Найти отверстия в структурах C из-за выравнивания - PullRequest
10 голосов
/ 06 октября 2011

Есть ли способ в gcc или clang (или любом другом компиляторе) выплевывать информацию о том, есть ли в структуре дыры (выравнивание памяти)?

Спасибо.

ps: Если есть другой способ сделать это, пожалуйста, сообщите мне.

Ответы [ 7 ]

5 голосов
/ 06 октября 2011

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

Возможно, вы захотите прочитать "Ткни дырку и друзей" и объявление о дыре для получения дополнительной информации

1 голос
/ 18 июня 2015

Gimpel FlexeLint / PClint может сделать это.

$ cat tst.c
int main (void)
{
    struct {
        char c;
        double d;
        short s;
    } f = { 1, 2.0, 3 };

    return f.c;
}

будет сообщать

$ flexelint -w1 +e95? tst.c
FlexeLint for C/C++ (Unix) Vers. 9.00L, Copyright Gimpel Software 1985-2014

--- Module:   tst.c (C)
                _
        double d;
tst.c  5  Note 958: Padding of 7 byte(s) is required to align member on 8 byte
    boundary
    _
    } f = { 1, 2.0, 3 };
tst.c  7  Note 959: Nominal struct size (18 bytes) is not an even multiple of
    the maximum member alignment (8 bytes)
tst.c  7  Note 958: Padding of 6 byte(s) is required to align end of struct on
    8 byte boundary
1 голос
/ 06 октября 2011

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

#include <stddef.h>

struct test {
  typea a;
  typeb b;
  typec c;
};

int gapB = offsetof(struct test, b) - (offsetof(struct test, a) + sizeof(typea));
int gapC = offsetof(struct test, c) - (offsetof(struct test, b) + sizeof(typeb));

printf("Gap of b:%d/n", gapB);
printf("Gap of c:%d/n", gapC);

* Примечание: вы должны будете сделать это для каждых двух участников в вашей застрявшей.

0 голосов
/ 10 марта 2018

Вам нужен анализатор, который понимает структуры c / c ++ и включает в себя необходимые файлы для включения.

Как ответил @ roee-gavirel, я думаю, что более простое решение - создать тестовую программу для распечатки смещений

#include <stdio.h>
#include <stddef.h>

typedef struct tData {
  long   id;       /* 8 bytes */
  char   name[8];  /* 8 bytes */
  float  salary;   /* 4 bytes */
} tData;

tData d;

int main()
{
  size_t s_tData  = sizeof(tData);
  size_t s_id     = sizeof(d.id);
  size_t s_name   = sizeof(d.name);
  size_t s_salary = sizeof(d.salary);

  printf("sizeof(tData) = %zu\n\n", sizeof(d));

  printf("'id'     is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, id), s_id);
  printf("'name'   is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, name), s_name);
  printf("'salary' is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, salary), s_salary);

  printf("\n");

  if (s_tData != s_id + s_name + s_salary)
    printf("There is/are holes\n");

  return 0;
}
0 голосов
/ 06 октября 2011

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

0 голосов
/ 06 октября 2011

Вы можете обнаружить такие «дыры» с помощью макроса offsetof:

#include <stddef.h>

struct test {
  char a;
  int b;
};
...
printf("%zu", offsetof(struct test, b));

Если это печатает больше, чем 1, b явно имеет требования к выравниванию, и компилятор создает промежуток между.

Очевидно, что это происходит во время выполнения, а не во время компиляции, но вы можете написать сценарий, который создает аналогичный исходный файл, компилирует и запускает его до остальной части вашего проекта, а затем, основываясь на выводевы принимаете дальнейшие решения о том, как построить свой проект.

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

0 голосов
/ 06 октября 2011

Вы можете изучить этот вопрос, написав пробный код для конкретного struct, используя sizeof и &;если sizeof член nth не совпадает с адресом следующего члена минус адрес этого участника, то есть пробел.

...