С++ в Delphi - Добавление структуры и указателя

У меня есть этот макрос, определенный на C++;

    #define EXT_FIRST_EXTENT(__hdr__) \
((struct ext4_extent *) (((char *) (__hdr__)) +         \
                         sizeof(struct ext4_extent_header)))

Где ext4_extent_header — это структура;

    typedef struct ext4_extent_header {
    uint16_t  eh_magic;       /* probably will support different formats */
    uint16_t  eh_entries;     /* number of valid entries */
    uint16_t  eh_max;         /* capacity of store in entries */
    uint16_t  eh_depth;       /* has tree real underlying blocks? */
    uint32_t  eh_generation;  /* generation of the tree */
}__attribute__ ((__packed__)) EXT4_EXTENT_HEADER;

И ext4_extent тоже является структурой;

typedef struct ext4_extent {
    uint32_t ee_block; /* first logical block extent covers */
    uint16_t ee_len; /* number of blocks covered by extent */
    uint16_t ee_start_hi; /* high 16 bits of physical block */
    uint32_t ee_start_lo; /* low 32 bits of physical block */
} __attribute__ ((__packed__)) EXT4_EXTENT;

Это моя попытка написать это в Delphi;

function Ext2Partition.EXT_First_Extent(hdr: PExt4_extent_header):PExt4_ExtEnt;
begin
  Result := PExt4_ExtEnt(hdr + sizeof(ext4_extent_header));
end;

Однако компилятор говорит мне, что оператор не применим к этому типу операнда.

Вот моя преобразованная структура С++ в записи Delphi для ext4_extent_header и ext4_extent;

Type
  PExt4_extent_header = ^Ext4_extent_header;
  Ext4_extent_header = REcord
    eh_magic : Word;
    eh_entries : Word;
    eh_max : Word;
    eh_depth : Word;
    eh_generation : Cardinal;
  End;

Type
  PExt4_ExtEnt = ^Ext4_ExtEnt;
  Ext4_ExtEnt = Record
    ee_block : Cardinal;
    ee_len : Word;
    ee_start_hi : Word;
    ee_start_low : Cardinal;
  End;

Спасибо!


person Jake Evans    schedule 11.02.2015    source источник
comment
Попробуйте с Cardinal(hdr) + sizeof....   -  person 500 - Internal Server Error    schedule 11.02.2015
comment
Так как Pascal является строго типизированным языком, вы должны явно преобразовать ptr в тип Cardinal (или в тип UIntPtr для большего удобства): Result := PExt4_ExtEnt(UIntPtr(hdr) + sizeof(ext4_extent_header));   -  person Abelisto    schedule 11.02.2015
comment
Также вы должны использовать packed record вместо record, потому что директива __packed__ в исходном коде C.   -  person Abelisto    schedule 11.02.2015


Ответы (2)


Приведите hdr так же, как код C++. Он приводит к указателю на октет, так что арифметика указателя обрабатывает смещение как значение октета. В Делфи:

Result := PExt4_ExtEnt(PAnsiChar(hdr) + sizeof(ext4_extent_header));

Вы можете включить арифметику указателя и сделать ее еще проще:

{$POINTERMATH ON}
....
Result := hdr + 1;

Вероятно, в вашем коде есть еще одна проблема. Если бы hdr действительно было PExt4_ExtEnt, то C++ не нуждался бы в макросе. Можно было просто написать hdr + 1. Поэтому я подозреваю, что вам нужно копнуть глубже в код C++, чтобы узнать, что такое hdr на самом деле.


Обратите также внимание на то, что код C++ указывает, что эти записи упакованы. Используйте packed record в коде Delphi для соответствия.

person David Heffernan    schedule 11.02.2015
comment
Не уверен, что преобразование указателя в какой-то более сложный тип, тогда Cardinal, является правильным способом, только потому, что SizeOf возвращает размер в байтах, но увеличение указателя PType(p) увеличивает его до размера TType (просто попробуйте изменить PAnsiChar на PWideChar в вашем примере и сравните Результаты). - person Abelisto; 11.02.2015
comment
Хотя ваше предложение теперь позволило скомпилировать мой код, я получаю разные результаты в Result по сравнению с кодом C++. На самом деле память в Result совершенно неправильная. - person Jake Evans; 11.02.2015
comment
@Abelisto PAnsiChar традиционно является типом, для которого доступна арифметика указателей. Это довольно хорошо известная идиома. Вы можете использовать NativeUInt, если хотите. PWideChar будет ошибкой. Не делай этого. Кроме того, я вообще не превращаюсь в кардинала. - person David Heffernan; 11.02.2015
comment
@ Джейк, я предполагаю, что ты не упаковал записи. - person David Heffernan; 11.02.2015
comment
@DavidHeffernan - я действительно упаковал записи после того, как вы предложили это в своем ответе. - person Jake Evans; 11.02.2015
comment
Так что сделайте некоторую отладку дальше. Вызовите макрос и функцию delphi, передавая NULL и nil соответственно. Ответы должны быть одинаковыми. Проверьте совпадения sizeof для обеих записей на двух языках. Как только все сходится, ваш дефект в другом месте. - person David Heffernan; 11.02.2015
comment
Смотрите мое последнее обновление. Если hdr - это то, что вы утверждаете, макрос не нужен. Так что я думаю, что ваши проблемы теперь в другом. - person David Heffernan; 11.02.2015
comment
Я только что снова обновил вопрос. hdr = ext4_extent_header - person Jake Evans; 11.02.2015
comment
Я откатился. Пожалуйста, можем ли мы придерживаться вопроса, который был задан и на который был дан ответ. Пожалуйста, сделайте отладку, которую я описал. Наконец, я не имею в виду тип hdr в коде паскаля. Я имею в виду код C++. Если бы это действительно был указатель на заголовок экстента, макрос не понадобился бы. Все же давайте сконцентрируемся на вопросе, пожалуйста. - person David Heffernan; 11.02.2015
comment
Я починил это. Ты был прав. Я передавал header не как указатель, а как указатель без ссылки. Спасибо. - person Jake Evans; 11.02.2015
comment
Настоящая хитрость при столкновении с такой проблемой состоит в том, чтобы разбить ее на мелкие части. Продолжайте доказывать, что каждая часть работает. По мере того, как вы это делаете, вы сужаете, где может быть ошибка. - person David Heffernan; 11.02.2015

1) Измените свою функцию на

function Ext2Partition.EXT_First_Extent(hdr: PExt4_extent_header):PExt4_ExtEnt;
begin
  Inc(hdr, 1); // It will increase _local copy_ of the hdr parameter to size of Ext4_extent_header, not to 1 byte. Keep in mind such behavior 
  Result := hdr;
end;

2) Куда после этого будет указывать Результат? Что находится сразу после hdr?

person Abelisto    schedule 11.02.2015