APPFS
Advanced practical programming for scientists
 All Data Structures Files Functions Variables Typedefs Macros
Macros | Functions
ex1a3.c File Reference

Appfs Exercise 1: direct read input, split main into several functions. More...

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>

Go to the source code of this file.

Macros

#define MAX_NUMS   ((INT32_MAX >> 5) + 1)
 Maximum number of 32 bit ints we need to store bits. More...
 
#define BUF_NUMS   4096
 read buffer size More...
 

Functions

static bool is_little_endian (void)
 Check if the architecture is little endian. More...
 
static int32_t reverse_int32 (int32_t val)
 Reverse the 4 bytes of an int between little and big endian. More...
 
static int store_numbers (const char *filename, uint32_t *have_num, const unsigned int max_nums)
 Read numbers from file and set bits in provided array. More...
 
static void output_numbers (FILE *fp, uint32_t *have_num, const unsigned int max_nums)
 Read through the marked bits and print out the numbers in ascending order. More...
 
int main (int argc, char **argv)
 Program to read a file with binary positive 32 bit integers, sort the numbers and print them sorted. More...
 

Detailed Description

Author
Thorsten Koch
Date
24Oct2014

gcc -O3 -Wall -std=c99 -o ex1a3 ex1a3.c

Using direct read() for input Improvements to ex1a2: Split main into several functions.

Definition in file ex1a3.c.

Macro Definition Documentation

#define BUF_NUMS   4096

Definition at line 23 of file ex1a3.c.

#define MAX_NUMS   ((INT32_MAX >> 5) + 1)

Definition at line 22 of file ex1a3.c.

Function Documentation

static bool is_little_endian ( void  )
inlinestatic

This check is constant and can be optimized away by the compiler during compile time. All conditionals depending on it are then decided at compile time

Returns
true if the machine uses little endian, false otherwise.

Definition at line 30 of file ex1a3.c.

31 {
32  union { uint32_t u; char c[sizeof(uint32_t)]; } bint = { 0x01020304 };
33 
34  return bint.c[0] == 4;
35 }
int main ( int  argc,
char **  argv 
)

Actually, the numbers are not sorted. There is an array with one bit for each possible number. Upon reading the respective bit is set for the number recognized. At the end the array is scanned in order and the numbers present are printed.

Parameters
argv[1] name of file to read

Definition at line 148 of file ex1a3.c.

149 {
150  const char* usage = "usage: %s filename\n";
151 
152  /* made static, because otherwise, the stack size might be too small.
153  */
154  uint32_t* have_num;
155  int total_nums;
156 
157  /* Check arguments, we need a filename.
158  */
159  if (argc < 2)
160  {
161  fprintf(stderr, usage, argv[0]);
162  exit(EXIT_FAILURE);
163  }
164  if (NULL == (have_num = calloc(MAX_NUMS, sizeof(*have_num))))
165  {
166  fprintf(stderr, "calloc of size %lu failed\n", MAX_NUMS * sizeof(*have_num));
167  exit(EXIT_FAILURE);
168  }
169 
170  if (0 > (total_nums = store_numbers(argv[1], have_num, MAX_NUMS)))
171  exit(EXIT_FAILURE);
172 
173  fprintf(stderr, "Total numbers read = %d\n", total_nums);
174 
175  output_numbers(stdout, have_num, MAX_NUMS);
176 
177  free(have_num);
178 
179  return EXIT_SUCCESS;
180 }
static void output_numbers(FILE *fp, uint32_t *have_num, const unsigned int max_nums)
Read through the marked bits and print out the numbers in ascending order.
Definition: ex1a3.c:125
static int store_numbers(const char *filename, uint32_t *have_num, const unsigned int max_nums)
Read numbers from file and set bits in provided array.
Definition: ex1a3.c:52
#define MAX_NUMS
Maximum number of 32 bit ints we need to store bits.
Definition: ex1a3.c:22
static void output_numbers ( FILE *  fp,
uint32_t *  have_num,
const unsigned int  max_nums 
)
static
Parameters
fpoutput file pointer.
have_numarray of size #max_nums * sizeof(*have_num)
max_numsmaximum number of entries in have_num

Definition at line 125 of file ex1a3.c.

129 {
130  assert(NULL != fp);
131  assert(NULL != have_num);
132 
133  for(int i = 0; i < max_nums; i++)
134  if (have_num[i]) // just for speed up
135  for(int k = 0; k < 31; k++)
136  if (have_num[i] & (1 << k))
137  fprintf(fp, "%d\n", (i << 5) + k);
138 }
static int32_t reverse_int32 ( int32_t  val)
inlinestatic

Byte order 1 2 3 4 ist reversed to 4 3 2 1

Parameters
valvalue to be reversed
Returns
reversed value

Definition at line 42 of file ex1a3.c.

43 {
44  val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
45 
46  return (val << 16) | ((val >> 16) & 0xFFFF);
47 }
static int store_numbers ( const char *  filename,
uint32_t *  have_num,
const unsigned int  max_nums 
)
static
Returns
the total number of numbers read. Be aware that some of the numbers may have beend discarded.
Parameters
filenamePath/Name of file to read
have_numarray of size #max_nums * sizeof(*have_num)
max_numsmaximum number of entries in have_num

Definition at line 52 of file ex1a3.c.

56 {
57  int32_t buf[BUF_NUMS];
58  int fd;
59  int n;
60  int total_nums = 0;
61 
62  assert(NULL != filename);
63  assert(0 < strlen(filename));
64  assert(NULL != have_num);
65  assert(0 < max_nums);
66 
67  /* Open file
68  */
69  if (0 > (fd = open(filename, O_RDONLY)))
70  {
71  perror(filename);
72  return -1;
73  }
74 
75  /* Read from file until data exhausted
76  */
77  while(0 < (n = read(fd, buf, sizeof(buf))))
78  {
79  int nums_read = n / sizeof(buf[0]);
80 
81  assert(nums_read <= BUF_NUMS);
82 
83  total_nums += nums_read;
84 
85  /* Run through buffer of read numbers and set mark bits
86  */
87  for(int i = 0; i < nums_read; i++)
88  {
89  int32_t num = buf[i];
90 
91  if (!is_little_endian())
92  num = reverse_int32(num);
93 
94  // fprintf(stderr, "%d\n", num);
95 
96  /* Check input: really >= 0 ? Otherwise ignore
97  */
98  if (num >= 0)
99  {
100  int idx = num >> 5; // n / 32
101  uint32_t msk = 1 << (num & 31); // bit number n mod 32
102 
103  assert(idx >= 0 && idx < max_nums);
104 
105  have_num[idx] |= msk;
106  }
107  }
108  }
109  /* man close(2):
110  * Not checking the return value of close() is a common but nevertheless serious programming error.
111  * It is quite possible that errors on a previous write(2) operation are first reported at the
112  * final close(). Not checking the return value when closing the file may lead to silent loss of data.
113  * This can especially be observed with NFS and with disk quota.
114  */
115  if (close(fd))
116  {
117  perror("close: ");
118  return -2;
119  }
120  return total_nums;
121 }
static int32_t reverse_int32(int32_t val)
Reverse the 4 bytes of an int between little and big endian.
Definition: ex1a3.c:42
static bool is_little_endian(void)
Check if the architecture is little endian.
Definition: ex1a3.c:30
NUMS * nums_read(const char *filename)
Read numbers into data structure.
Definition: nums.c:52
#define BUF_NUMS
read buffer size
Definition: ex1a3.c:23