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;
}
Другие вопросы по тегам