Marshal.AllocHGlobal выделяет больше памяти, чем ожидалось - PullRequest
2 голосов
/ 25 мая 2019

Я использую метод Marshal.AllocHGlobal c # для выделения памяти для IntPtr, а затем копирую содержимое байта []:

byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = IntPtr.Zero;
ipAddress_p = Marshal.AllocHGlobal(clientIpAddr.Length);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);

Затем я передаю указатель во внешнюю библиотеку C ++, которая получает мойпеременная, подобная этой:

int open_socket(char *clientIpAddr_p)
{
    <open a socket>
}

В соответствии с определением AllocHGlobal это в конечном итоге может зарезервировать больше памяти, чем ожидалось (что я могу заверить, потому что теперь я страдаю от этого).Проблема в том, что мне нужно, чтобы мой IntPtr имел точно такой размер, который я запрашиваю, потому что мне нужен точный IP-адрес для последующего открытия сокета.

Есть ли лучший способ выделить внешнюю память, обеспечивающуюchar * чтобы у меня был правильный IP?

1 Ответ

4 голосов
/ 25 мая 2019

Это не проблема, что Marshal.AllocHGlobal выделяет больше указанного объема памяти. Ваш код страдает от другой и вполне вероятной фатальной проблемы.

open_socket(char *clientIpAddr_p) ожидает указатель на C-стиль строку с нулевым символом в конце (также известную как строка с нулевым символом в конце, строка с нулевым символом или ASCIIZ). Однако ваш код C # создает буфер и заполняет его строковыми символами / байтами, не заканчивая его нулевым символом. Вполне возможно, что это приведет к аварийному завершению функции open_socket или неправильному поведению при поиске в памяти (начиная с адреса, указанного указателем) отсутствующего нулевого символа.

Возможное исправление будет довольно простым: выделите буфер размером clientIpAddr.Length + 1 с учетом завершающего нулевого символа. Терминатор нуля (нулевой байт) должен быть установлен явно, поскольку Marshal.AllocHGlobal не не инициализирует / заполняет выделенный буфер нулевыми байтами. Поскольку здесь мы имеем дело со строкой ASCII / ANSI, нулевой символ - это просто байт со значением ноль.

byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = Marshal.AllocHGlobal(clientIpAddr.Length + 1);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);
Marshal.WriteByte(client_ipAddr_p, clientIpAddr.Length, 0);


Хорошо, забудьте о коде, который я только что написал. ; -) * 1 021 *

Почему? Поскольку существует еще более простое «универсальное» решение проблемы, избавляющее вас от необходимости вручную выделять и заполнять буфер для строки с нулевым символом в стиле C: Marshal.StringToHGlobalAnsi метод, который преобразует вашу строку .NET с IP-адресом непосредственно в соответствующую строку ANSI с нулевым символом в конце в стиле C.

string ipAddress = "127.0.0.1";
IntPtr client_ipAddr_p = Marshal.StringToHGlobalAnsi(ipAddress);

(Если функция open_socket не требует, чтобы строковый буфер, на который указывает clientIpAddr_p , продолжал существовать после его вызова, освободите выделенный буфер с помощью метода Marshal.FreeHGlobal после вызова собственной функции независимо от того, был ли буфер выделен с помощью Marshal.AllocHGlobal или Marshal.StringToHGlobalAnsi .)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...