Skip to content
This repository has been archived by the owner on Jan 12, 2022. It is now read-only.

L22 [Misc Topics]

Skyline-9 edited this page Nov 30, 2021 · 1 revision

Control Flow

There is a goto in C but it isn't recommended for many reasons

  • Optimization
  • Performance
  • Clarity

Plus it will only jump within a single function. Even worse, there is a library that lets you jump anywhere

#include <setjmp.h>

jmp_buf x; //Hold location x
t = setjmp(x); //Mark a location as x, t will be 0 for normal control flow, non-zero if coming back from longjmp()

longjmp(x, 3); //Transfer back to location x, and setjmp will have return value 3

A call to setjmp() saves various information about the calling environment (typically, the stack pointer, the program counter, possibly the values of other registers and the signal mask) in the jmp_buf and returns 0

longjmp() must be called later in the function OR in a function that’s called by the function that did the setjmp(). In other words, the stack frame of the function that called setjmp() must still be on the stack (somewhere) when longjmp() is called.

longjmp() restores the saved CPU state from jmp_buf while setting the return value to the value in its second argument

  • This makes it appear as if setjmp() returns for a SECOND time without being called again, distinguished only by its return value!

Variadic Functions

How do we get printf() to have all these different types of arguments and parameters?

printf("Count %d, average %f\n", ct, avg);
printf("%d %d %d %d\n", a[0], a[3], a[2], a[1]);

Welcome stdarg.h

#include <stdarg.h>

void printargs(int arg1, ...);

int main(void) {
   printargs(5, 2, 14, 84, 97, 15, -1, 48, -1;(
   printargs(84, 51, -1;(
   printargs(-1;(
   printargs(1, -1;(
   return 0;
}

void printargs(int arg1(... ,
{
  va_list ap;
  int i;
  va_start(ap, arg1 ;(
  for (i = arg1; i >= 0; i = va_arg(ap, int((
    printf("%d ", i;(

  va_end(ap;(
  putchar('\n;('
}

And the result...

$ ./a.out

5 2 14 84 97 15
84 51
1
int main(void)
{
   printargs(5, 2, 14, 84, 97 ,
            ;(1- ,48 ,1- ,15
   printargs(84, 51, -1;(
   printargs(-1;(
   printargs(1, -1;(
   return 0;
}

Main Return Value

  • 0 means okay
  • Anything else means a problem
  • Any function can exit with exit(99) a set whatever return value
  • You can check this value on the command line with echo $?

File I/O

Default Streams

  • stdin – Standard input
  • stdout – Standard output – printf(...) defaults to stdout
  • stderr – Standard error output – use fprintf(stderr, ...)
FILE *infile;
if((infile = fopen(“f.txt”,”r”)) == NULL){
  // Handle error
}

For stdout the output is line-buffered if it’s written to a terminal and block-buffered if it’s written to to a disk file

  • BufferOutput not flushed if your program crashes
printf(“Checkpoint 1”);
fflush(stdout);

However, for stderr, the output is not buffered, so output will always cause immediate I/O

fprintf(stderr, “Checkpoint 1”);

The reason output is buffered by default is to reduce the number of I/O traps the operating system has to process

Inline Functions

You can have inline functions that are essentially text-substituted into where you call them from

inline int myfunc(int a, int b) {
  return a + b;
}

Optimization

You can use the -O flag to control optimization

  • 0 is don't move code around (default)
  • 1 is quick optimizations that don't take much compile time
  • 2 is all optimizations that don't involve speed/space tradeoff
  • 3 is max optimization

Don't write tricky code designed to be very efficient

  • Until they’ve measured it, programmers rarely know where the CPU is spending its time in their code; this is called premature optimization

Profiling is program means instrumenting and measuring a running program to discover where the CPUs spend their time in order to find the most effective places to optimize the code