GetPrivateProfileString - класс c ++ - возвращаемая строка - предварительный расчет памяти - PullRequest
1 голос
/ 19 октября 2010

В GetPrivateProfileString, lpReturnedString возвращает строковое значение, присутствующее в ключе определенного раздела INI-файла.

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

DWORD WINAPI GetPrivateProfileString(
  __in   LPCTSTR lpAppName,
  __in   LPCTSTR lpKeyName,
  __in   LPCTSTR lpDefault,
  __out  LPTSTR lpReturnedString,
  __in   DWORD nSize,
  __in   LPCTSTR lpFileName
);

Ответы [ 3 ]

2 голосов
/ 19 октября 2010

Стандартный регистр

Возвращаемое значение из GetPrivateProfileString - это количество символов, скопированных в буфер, не включая нулевой терминатор.

Следовательно, вы можете начать с (скажем) aбуфер 100 _TCHAR с и проверьте возвращаемое значение.Если это 99, то либо вы точно угадали размер строки, либо (что более вероятно) ваш буфер слишком мал, поэтому увеличьте его и повторите попытку.

«Перечисление» case

Вышеприменяется к стандартному случаю получения одного строкового значения из файла .ini.Если вместо этого вы передаете NULL в качестве параметров lpAppName или lpKeyName, чтобы перечислить все доступные значения, и вы указали слишком малый размер буфера, возвращаемое значение будет two меньше размера буфера.

Стратегия размещения

Вам нужно будет динамически распределять буфер.Таким образом, вы, вероятно, будете использовать std::auto_ptr или std::unique_ptr, или, возможно, std::vector<_TCHAR>, который вы можете resize() по мере необходимости.Если вы не знаете заранее, насколько большими будут строки, я бы порекомендовал начать с чего-то вроде 250 _TCHAR с и удваивать размер каждый раз, когда вы обнаружите, что буфер слишком мал.На практике, я бы поспорил, что 250 достаточно в 99,9999% случаев.

Альтернативы

XML-файл, хранящийся в %APPDATA%;Файл JSON хранится в %APPDATA%, Реестр…

2 голосов
/ 19 октября 2010

Исходя из вашего вопроса, я предполагаю, что вы хотите выделить память в куче с new, malloc, LocalAlloc или какой-либо другой функцией, работающей с кучей. Возможно, вы хотите использовать как можно меньше кучи памяти.

Если вы работаете с памятью в стеке , это не так важно, чтобы быть так точно. Выделение памяти очень быстро (примерно в 100 или 1000 раз быстрее, чем в куче), и после возврата из текущей функции память будет автоматически освобождена. Таким образом, вы можете просто определить переменную

TCHAR szBuffer[16384];

16K в стеке - это почти ничто. Затем вы можете позвонить GetPrivateProfileString с szBuffer как lpReturnedString. Функция GetPrivateProfileString возвращает количество символов, скопированных в буфер. Если значение меньше 16K-1, вы будете знать точный размер буфера. Теперь вы можете выделить блок памяти размером в куче и скопировать данные из szBuffer в блок. Если возвращаемое значение GetPrivateProfileString равно 16K-1, то у вас слишком маленький буфер. В этом случае вы можете реализовать любое удвоение размера буфера (и теперь работать с буфером кучи), но я предпочитаю интерпретировать это как как ошибку в ini-файле . Все настоящие ini-файлы, которые я использовал ранее, были небольшими. Размер записи в основном не превышает 260 символов. Таким образом, размер входной терки как 16K можно интерпретировать как ошибку.

Кстати, вы можете проверить размер INI-файла в отношении GetFileSizeEx . Размер записи должен быть меньше размера INI-файла.

Некоторое ограничение на размер INI, которое вы должны включить в свою программу. Если размер записи будет измеряться в ГБ, то вы можете получить проблему. Почему бы не ограничить размер разрешенной записи, например, 16K?

2 голосов
/ 19 октября 2010

Это странно, как правило, функции Windows API позволяют передавать значение NULL и возвращать вам размер для создания буфера. Эта функция, кажется, не делает этого. Я бы сказал, что вы должны просто выбрать разумный размер. Если он недостаточно большой, удваивайте размер буфера, пока не получите его.

...