Вы можете записать в байтовый массив, используя FILE * - PullRequest
1 голос
/ 19 июля 2009

C # обладает удобной возможностью записи в поток памяти с использованием объекта MemoryStream.

Я ищу аналогичную функциональность в C, используя указатель FILE *.

Я хочу иметь возможность sprintf (), но с добавленной функциональностью C помнит "где я был" в буфере, в который я пишу.

Ответы [ 6 ]

5 голосов
/ 19 июля 2009

Если вы используете библиотеку GNU C, вы можете использовать fmemopen () . Могут быть и другие непереносимые расширения для других сред, но нет переносимого способа использования FILE * s.

Вы также можете, однако, обернуть snprintf, если вы не настаиваете на фактическом использовании FILE * s. Например, glib (примечание: не то же самое, что библиотека GNU C, и переносимая версия) имеет g_string_append_printf , который делает то, что вы хотите.

3 голосов
/ 19 июля 2009

Существует также уродливый хак, который работает с простым ISO-C: вы можете использовать fopen(), чтобы открыть пустой файл (/dev/null на * nix, NUL на Windows) и установить массив в качестве буфера файла через

setvbuf(file, buffer, _IOFBF, buffer_size)

Это должно работать нормально, если fflush() нигде в коде не вызывается. Кроме того, программист должен явно позаботиться о строковом разделителе.

Я не вижу необходимости делать это, хотя: * snprintf() возвращает количество написанных символов, тривиально отслеживать положение буфера.

Можно даже написать функцию для автоматического изменения размера буфера при переполнении: bufprintf.c

Прототип функции -

int bufprintf(char **buffer, size_t *size, size_t *offset,
    const char *format, ...);

Пример программы может выглядеть так:

#include <stdio.h>

extern int bufprintf(char **buffer, size_t *size, size_t *offset,
    const char *format, ...);

int main(void)
{
    size_t size = 0; // must be set!
    size_t offset;
    char * buffer;

    for(int i = 0; i < 100; ++i)
        bufprintf(&buffer, &size, &offset, "we rock %i\n", i);

    puts(buffer);
    printf("size:\t%u\noffset:\t%u\n", (unsigned)size, (unsigned)offset);
}
2 голосов
/ 19 июля 2009

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

buffer += sprintf(buffer, "%d", i);

Убедитесь, что вы храните копию исходного указателя, поскольку именно это вы будете использовать при передаче буфера куда-то еще.

0 голосов
/ 19 июля 2009

Как насчет простого управления указателями вручную. Передо мной нет компилятора, но, надеюсь, приведенный ниже код поможет понять:

char huge_buffer[REALLY_BIG_SIZE];
char *write_pos = huge_buffer;

//...

void fprintf_to_mem(char **mem_ptr, const char *fmt, ...)
{
  va_list args;
  int num_written;

  va_start(args, mem_ptr);
  num_written = vsprintf(*write_pos, fmt, args);
  *write_pos += num_written;

  va_end(args);
}

//...

fprintf_to_mem(&write_pos, "Testing %d %d %d", 1, 2, 3);
fprintf_to_mem(&write_pos, "Hello world!\r\n");  

Я ожидаю, что для вывода "Testing 1 2 3Hello world! \ R \ n" в огромный_буфер.

0 голосов
/ 19 июля 2009

MemoryStream не является особенностью языка C #. Это просто класс в BCL. Вы можете написать это сами на C #.

Так же и в C - вы бы написали некоторые функции, которые работают аналогично при использовании fopen, fprintf, fwrite, fclose и т. Д., Но дали бы им имена, например mopen mwrite и т. Д. (Предположительно) и запишите их так, чтобы они работали с буфером памяти.

0 голосов
/ 19 июля 2009

Почему бы не использовать mmap? Вы можете отобразить файл в память и использовать указатель FILE *.

Обновление: не работает. К сожалению.

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