Всем привет! Столкнулся с интересной ситуацией. Так как я не очень часто трогаю Desktop языки, то раньше почти не работал с указателями и памятью кроме динамических массивов. Сейчас пишу утилиту для себя, получаю список сетевых интерефейсов и ARP таблицу.
function MyGetIpNetTable(): PMIB_IPNETTABLE;
var
ipTable : PMIB_IPNETTABLE;
size : Dword;
Buffer, ptSeek: PByte;
begin
GetIpNetTable(nil, size, True); //После первого вызова в size попадает необходимый размер буфера
GetMem(Buffer, size);
ShowMessage('IpNetTable size: ' + IntToStr(size));
ipTable := PMIB_IPNETTABLE(Buffer);
case GetIpNetTable(ipTable, size, True) of
NO_ERROR:
begin
ShowMessage('GetIpNetTable no error');
Result := ipTable;
end;
else
begin
Result := nil;
end;
end;
end;
Первым вызовом GetIpNetTable определяю размер буфера, выделяю память, вторым вызовом получаю данные. Код копейка в копейку с официальной доки microsoft. Но когда в дальнейшем я пробую перебирать таблицу ipTable.table обычным циклом for, то сразу после первого элемента получаю out of range, как будто он не может вычислить адрес следующего элемента.
ipTable := MyGetIpNetTable();
ptSeek := @ipTable.table;
for var i := 0 to ipTable.dwNumEntries - 1 do
begin
ShowMessage(IntToStr(ipTable.table[i].dwIndex));
end;
Однако, если я сделаю то же самое вручную, увеличивая указатель на фиксированный размер строки в таблице (_MIB_IPNETROW), то всё прекрасно работает.
ifTable := MyGetIfTable();
ptSeek := @ifTable.table;
for var i := 0 to ifTable^.dwNumEntries - 1 do
begin
ifRow := PMIB_IFROW(ptSeek);
try
ListBox1.Items.Add(TEncoding.UTF8.GetString(ifRow.bDescr));
ifIndexes[i] := ifRow.dwIndex;
Except
on Exception do
ListBox1.Items.Add('?????')
end;
ptSeek := ptSeek + SizeOf(_MIB_IFROW);
end;
Всю кукушку сломал, и на листочке рисовал - не понимаю, почему по индексу обращаться не получается, а прибавляя размер структуры вручную - получается?
Я понял, что это как-то связано с padding, но как именно?
(тут представлены куски 2-х функций, но с ними одинаковая история абсолютно)