Я пишу оболочку, которая разветвляет процесс execv()
. Выходные данные дочернего элемента фиксируются в stderr
. Когда waitpid()
выйдет, я смогу прочитать содержимое stderr
и сообщить об этом.
В моем случае я хочу динамически выделить буфер и записать в этот буфер stderr
.
Для размера буфера я могу realloc()
, но это не очень эффективно, и я обнаружил, что это имеет тенденцию к раздуванию использования пула памяти. Скорее, я хотел бы знать размер, не меняя указатель.
Рассмотрим следующее и обратите внимание, что MyStderr
— это просто заполнитель для stderr
:
int size=0;
int ch=0;
// int MyStderr is the stderr fd
FILE *nCountFD = fdopen(MyStderr, "r");
while ((ch = getc(nCountFD)!=EOF)
{
++size;
}
printf("Size is %ld\n", size);
Вот и узнаю размер. Однако теперь указатель файла для MyStderr
находится в конце его буфера.
Я пытался использовать lseek
.
lseek()
терпит неудачу против stderr
, поэтому я не могу использовать его здесь. По крайней мере, на это указывает мое тестирование и поиск в стеке.
So ...
- Есть ли способ получить размер, не перемещая
MyStderr
в eof?
or
- Есть ли метод
lseek
, который будет работать сMyStderr
?
Примечание. Вот единственное решение, которое я могу придумать, используя realloc
..
char *buf=(char*)malloc(80);
char *NewBuf=NULL;
int n=80;
while ((ch = getc(nCountFD)!=EOF)
{
buf[i]=ch;
++size;
if (size>n)
{
n=n+80;
NewBuf= realloc(buf, n);
// some code to make sure it works here //
buf=NewBuf;
}
}
printf("Size is %ld\n", size);
А теперь обновление
Вместо того, чтобы создавать функциональность для обхода того факта, что stderr не буферизован, я решил сделать начальный malloc моего буфера результатов достаточно большим, чтобы в большинстве случаев использование realloc() было маловероятным. И если происходит realloc(), размер исходного распределения удваивается для каждого realloc(), как было предложено.
При тестировании (100 000 итераций) это работает очень хорошо, без утечек или заметного вздутия.
Я многим обязан сообществу Stack Overflow. Спасибо вам всем.
Приведенный ниже код не будет работать автономно. Он размещен здесь, чтобы проиллюстрировать то, что я сделал.
.. после всего кода, который анализирует командную строку, разветвляется, выполняет execv и очищает...
while (waitpid(nPID, &status, 0) != nPID)
;
i = 0;
nFD = fdopen(nErrFD, "r");
if (!nFD) {
snprintf(cErrMsg, 80, "Cannot open fd[%i]. Failed to spaw process",
nErrFD);
cbuf = strcpy(cbuf, cErrMsg);
goto NECerror;
}
close(nErrFD);
cbuf = calloc(nBufSz, sizeof(char));
memset(cbuf, 0x00, nBufSz);
i = 0;
while ((ch = getc(nFD)) != EOF) {
cbuf[i] = (char) ch;
++size;
++i;
if (size > nBufSz) {
nBufSz = nBufSz + nBaseBufSz;
NewBuf = realloc(cbuf, nBufSz);
if (NewBuf == NULL) {
snprintf(cErrMsg, 80,
"Internal error:cannot allocate [%i] bytes", nBufSz);
cbuf = strcpy(cbuf, cErrMsg);
fclose(nFD);
goto NECerror;
}
cbuf = NewBuf;
free(NewBuf);
}
}
fclose(nFD);
realloc()
ating памяти может быть уменьшена, если вы используете экспоненциальное увеличение, но линейное. Поэтому не просто добавляйте постоянное количество символов, а удваивайте объем памяти, выделенной от перераспределения к перераспределению. В конце вы можете поместить окончательнуюrealloc()
ation, которая затем сожмет выделенную память до действительно необходимого размера. - person alk   schedule 08.02.2012