Applying C - File Descriptors
Written by Harry Fairhead   
Monday, 24 August 2020
Article Index
Applying C - File Descriptors
Permissions & Random Access
fcntl
The Reader

There is the C way of working with files and there is the Linux way - sometimes you just need to use the Linux file descriptor. This extract is from my  book on using C in an IoT context.

Now available as a paperback or ebook from Amazon.

Applying C For The IoT With Linux

  1. C,IoT, POSIX & LINUX
  2. Kernel Mode, User Mode & Syscall
  3. Execution, Permissions & Systemd
    Extract Running Programs With Systemd
  4. Signals & Exceptions
    Extract  Signals
  5. Integer Arithmetic
    Extract: Basic Arithmetic As Bit Operations
  6. Fixed Point
    Extract: Simple Fixed Point Arithmetic
  7. Floating Point
  8. File Descriptors
    Extract: Simple File Descriptors 
    Extract: Pipes 
  9. The Pseudo-File System
    Extract: The Pseudo File System
    Extract: Memory Mapped Files ***NEW
  10. Graphics
    Extract: framebuffer
  11. Sockets
    Extract: Sockets The Client
    Extract: Socket Server
  12. Threading
    Extract:  Pthreads
    Extract:  Condition Variables
    Extract:  Deadline Scheduling
  13. Cores Atomics & Memory Management
    Extract: Applying C - Cores 
  14. Interupts & Polling
    Extract: Interrupts & Polling 
  15. Assembler
    Extract: Assembler

Also see the companion book: Fundamental C

<ASIN:1871962609>

<ASIN:1871962463>

<ASIN:1871962617>

<ASIN:1871962455>

ACcover

There is a standard C approach to files, but there is also a POSIX standard that is implemented in Linux/Unix and in many ways this is more general than the C file functions. The reason is that once you move beyond files stored on disks, suddenly it is the POSIX approach to files that becomes the natural one to use. Of course, the C file handling functions are mapped onto the native file functions of the operating system and in the case of the POSIX system these are based on the use of a file descriptor. In most cases, however, you are better off using the standard C file functions as they are robust, easy to use and buffered.

In any particular implementation these functions are mapped to the file system calls that the operating system provides. The file pointer returned by fopen and used by the other file handling functions is actually a pointer to a structure that defines the file. However, this structure is supposed to be opaque in the sense that you are not supposed to make use of its internal structure, which may vary according to the operating system.

What all this means is that the C standard library file handling is a uniform wrapper around the varying file handling facilities provided by the operating system. If you can avoid using anything else your programs will have the advantage of being portable.

In this chapter it is assumed that you know the basics of file handling and, in particular, are familiar with the C standard file functions.

A brief summary of the C file functions is given in the table below:

Function

 

FILE *fptr=fopen(
filename”,”mode”);

Open a file. Mode determines how the file is opened and is any of:

r open for read

w open for write

a open for append

r+ open for reading and writing

w+ open for reading and writing
if the file exists it is overwritten

a+ open for reading and appending
if the file doesn’t exist it is created

fclose(fptr);

Close file

fprintf(fptr,"format string",
list of variables);

Works like printf but sends chars to file

fscanf(fptr,"format string",
                  &variable);

Works like scanf but reads chars from file

fputs(string,fptr);

Works like puts but sends string to file

fgets(string,length,fptr);

Works like gets but reads string from file

fread(ptrToBuffer, size, 
number, fptr);

Read number*size chars from file

fwrite(ptrToBuffer,size,
                number,fptr);

Write number*size chars from file

fputc(charAsint,fptr);
putc(charAsint, fptr);

Write a single character to a file

fgetc(fptr);
getc(fptr);

Read a single character from a file

ungetc(charAsint,fptr);

Undo a character read

fflush(fptr);

flush the file buffer

rewind(fptr);

Return file pointer to start of file

fseek(fptr,offset,whence);

Move file pointer to whence+offset

ftell(fptr);

Position of file pointer.

feof(fptr);

Test for end of file

File Descriptors

There are many occasions when you need to call functions that are provided by the operating system and if the call involves a file then it will generally need to be passed something that corresponds to the native way that the operating system works with files. While there is no overall standard for this, for Linux and other Unix-like operating systems we rely on POSIX.

A POSIX-conforming operating system uses a file descriptor rather than a file pointer. A file descriptor is a simple int that is an index into an internal operating system table of open files. Each process has its own table and each such table references a globally held table of files.

By default there are three predefined file descriptors:

STDIN_FILENO

STDOUT_FILENO

STDERR

which under Linux/Unix correspond to 0,1 and 2.

What all of this means is that most programs running under Linux, or any POSIX operating system, sooner or later have to abandon the C standard way of working with files. This is both good and bad news. The bad news is, of course, that this is not as portable. The good news is that it is a lower-level way of working with files that makes it possible to do more, in particular they are not buffered. The final piece of good news is that the POSIX functions, defined in unistd.h and fcntl.h are very similar to the C standard library files.

The open function, defined in fcntl.h:

open(filename,flags, mode);

opens the file and returns an int, the file descriptor. The flags and mode parameters control how the file is to be opened and file permissions to be set when the file is created. The flags are formed by the bitwise OR of one of:

O_RDONLY open for reading only

O_WRONLY open for writing only

O_RDWR open for reading and writing.

with any of the following optional arguments:

O_APPEND append on each write

O_CREAT create file if it does not exist

O_TRUNC truncate size to 0.

If you are creating a file you also have to supply the mode parameter. This is simply the Linux permissions code and, as this is usually presented to the end user in octal, you can also use octal. There are also a set of predefined macros that can be ORed together to set the permission you require. For example S_IRUSR sets the user read bit.



Last Updated ( Monday, 24 August 2020 )