Ansi C и временные файлы
Мне нужен целочисленный файловый дескриптор из временного файла, который будет использоваться в mmap. Эта потребность может потребоваться изменить, если нет простого способа сделать это, оставаясь при этом совместимым со стандартами.
Первоначально я получил поток FILE, используя:
FILE *tmpfile();
а потом использовал...
int fileno(FILE foo);
Все было хорошо, пока я не заметил следующее в справочной странице для fileno.
CONFORMING TO
The functions clearerr(), feof(), and ferror() conform to C89 and C99.
т.е. fileno не является частью c99. Я посмотрел в Интернете простой способ получить временное имя файла или его дескриптор файла таким образом, чтобы не выдавать ошибки при использовании
-std=c99 -pedantic
и пока лучшее, что я нашел, это:
http://www.di-mgt.com.au/c_function_to_create_temp_file.html
Я хотел бы знать, что другие люди делают, чтобы обойти это, и есть ли страница руководства, которую я где-то пропустил, или что-то очевидное, что я могу использовать в c99, который я пропустил?
Обновление: я написал небольшую тестовую программу, чтобы увидеть, где я ошибся. Прошу прощения за отсутствие проверки ошибок, я стараюсь, чтобы она была короткой. Я запустил это, используя clang и gcc на коробке Debian:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/mman.h>
int main(int argc, const char* const argv[])
{
const char *fname = argv[1];
/*
FILE *stream = fopen("foo", "wb+");
-std=c99 -pedantic fails on fileno
int fd = fileno(stream);
*/
int fd ;
if((fd = open(fname, O_RDWR| O_CREAT, 0644)) < 0) {
fprintf(stderr, "fd=%i, failed: %s\n",fd, strerror (errno));
exit(EXIT_FAILURE);
}
size_t fsize = 27;
char *buf;
lseek (fd, fsize - 1, SEEK_SET);
write (fd, "", 1);
lseek (fd, 0, SEEK_SET);
buf = mmap(0, fsize, PROT_WRITE, MAP_SHARED, fd, 0);
size_t i = 0;
for(i = 0; i < fsize; i++) {
buf[i] = i % 26 + 97;
}
buf[26] = '\n';
munmap(buf, fsize);
close(fd);
return argc;//Avoid warnings about unused variables
}
Запустите его с помощью clang или gcc, используя Bware rm -f в начале команды.
rm -f foo mmap; clang -Wall -Wextra -std=c99 -pedantic-errors -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition mmap.c -o mmap;./mmap foo;cat foo|wc -c
rm -f foo mmap; gcc -Wall -Wextra -std=c99 -pedantic-errors -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition mmap.c -o mmap;./mmap foo;cat foo|wc -c
Это работает, что означает, что я что-то упускаю из-за использования -std=c99 -pedantic, потому что я ожидал бы, что он с треском провалится, когда я попытаюсь включить любой нестандартный заголовок, т.е. в этом случае я бы ожидал ошибки, пытаясь включить их...
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
Мне было бы интересно узнать, почему вышеупомянутые программы компилируются, т.е. что-то устанавливается в заголовках, которые отключают предупреждения, или я злоупотребляю gcc?
2 ответа
Вы не можете достичь того, что вы хотите.
Документация для -pedantic
говорит:
Выпускать все предупреждения, требуемые строгими стандартами ISO C и ISO C++; отклонить все программы, которые используют запрещенные расширения, и некоторые другие программы, которые не соответствуют ISO C и ISO C++. Для ISO C следует версии стандарта ISO C, указанной любой используемой опцией -std.
Целочисленные файловые дескрипторы не являются частью стандарта C. Они из POSIX. Также нет mmap
в стандарте C это также происходит от POSIX. Итак -pedantic
Флаг предназначен, чтобы не позволять вам делать то, что вы хотите сделать. Я только что проверил заголовочные файлы и конфигурацию компилятора в моей системе, и они явно исключают (многие, но не все) функции POSIX, если вы компилируете с gcc -std=c99 -pedantic
,
Вы действительно хотите использовать этот флаг?
Для создания временного файла со стандартным C используйте tmpfile
тогда вместо mmap
нужно читать и писать файл с нормальным fread
а также fwrite
,
С помощью sort-bed
вот один из способов, который заполняет fileName
указатель с временным именем файла внутри path
и возвращает FILE*
:
FILE *
createTmpFile(char const* path, char** fileName)
{
FILE* fp;
int fd;
char* tmpl;
if (path == NULL)
{
fileName = NULL;
return tmpfile();
}
tmpl = (char*)malloc(1 + strlen(path) + L_tmpnam);
strcpy(tmpl, path);
strcpy(tmpl+strlen(path), "/sb.XXXXXX");
fd = mkstemp(tmpl);
if(fd == -1)
{
fprintf(stderr, "unable to create temp file!\n");
return NULL;
}
fp = fdopen(fd, "wb+");
*fileName = (char*)malloc(strlen(tmpl) + 1);
strcpy(*fileName, tmpl);
free(tmpl);
return fp;
}