cc99c89gcc-pedantic

Ansi C and Temporary Files


I need the integer file descriptor from a temporary file to be used in mmap. This need may need to change if there's no simple way to do this while still being standards compliant.

I originally got a FILE stream using:

FILE *tmpfile();

and then used...

int fileno(FILE foo);

All was good until I noticed the following in the man page for fileno.

CONFORMING TO
   The functions clearerr(), feof(), and ferror() conform to C89 and C99.

ie fileno is not part of c99. I've had a look online for a simple way to get a temporary filename or it's file descriptor in a way that doesn't throw errors when using

-std=c99 -pedantic

and so far the best thing I've found is:

http://www.di-mgt.com.au/c_function_to_create_temp_file.html

I'd love to know what other people are doing to get around this and is there a man page that I've missed somewhere or something obvious I can use in c99 that I've overlooked?

Update: I wrote a small test program to see where I went wrong. Please forgive the lack of error checking, I'm trying to keep it short. I've run this using clang and gcc on a Debian box:

#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
} 

The run it with either with clang or gcc using Beware the rm -f at the start of the command.

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

This works which means I'm missing something about the use of -std=c99 -pedantic because I would expect it to fail miserably when I tried to include any non standard header ie in this case I would have expected errors trying to include these...

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

I'd be interested in knowing why the above programs compiles ie is something being set in the headers that's turning off warnings or am I abusing gcc?


Solution

  • You can't achieve what you want.

    The documentation for -pedantic says:

    Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.

    Integer file descriptors are not part of the C standard. They are from POSIX. Also, there is no mmap in the C standard, it comes from POSIX too. So the -pedantic flag is designed to not allow you to do what you want to do. I just checked the header files and compiler configuration on my system and they explicitly exclude (many, but not all) POSIX functions if you're compiling with gcc -std=c99 -pedantic.

    Are you sure you really want to use that flag?

    To create a temporary file with standard C use tmpfile then instead of mmap you need to read and write the file with normal fread and fwrite.