C

From Rixort Wiki
Revision as of 08:18, 5 June 2023 by Paul (Sọ̀rọ̀ | contribs)
Jump to navigation Jump to search

Versions

Three major revisions of C:

  • ANSI C - also known as C89
  • C99
  • C11

Sample Makefile

CC=clang
CFLAGS=-Weverything
LDFLAGS=
SOURCES=hello.c
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=hello

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
	$(CC) $(LDFLAGS) $(OBJECTS) -o $@

.c.o:
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -rf *.o $(EXECUTABLE)

Encapsulation

Using the static keyword when defining a function will restrict that function to file-scope (likewise for variables).

Function parameters

Depending on the architecture, function parameters may be loaded into registers when the function is called. However, as the number of registers is small, even on RISC architectures, having more than 4-8 function parameters may impact performance.

Guaranteed data type sizes

Portable types such as uint16_t (unsigned integer, 16 bits) allow data type sizes to be guaranteed across platforms and are defined in stdint.h.

stdint.h is only guaranteed to exist in C99 onwards.

Compiler options

  • -D: Define this macro - e.g. -D_BSD_SOURCE is the same as including #define _BSD_SOURCE 1.

GCC warning flags

  • -Wall: Enables a large number of warnings, though not all (despite the name).
  • -Wextra: Enables extra warnings above and beyond -Wall.
  • -Werror: Make all warnings into errors. Effectively this means that code which produces warnings will fail to compile.

Clang warning flags

Clang supports most GCC warning flags, as well as some extras.

  • -Weverything: All warnings, may include new warnings in future versions (so code may compile under -Weverything now but not if clang is upgraded). If you include third party libraries, it is highly unlikely that your codebase will compile with this flag enabled.

Changes from C89 to C99

  • Support for C++ style single-line comments, i.e. // this is a comment.
  • Variables no longer have to be declared before code, e.g. for (int i = 0; i < 9, i++).
  • Support for variable length arrays, e.g. int a[b][c].

Cygwin

C programs compiled under Cygwin will depend on cygwin1.dll, regardless of whether any POSIX functions are used. You can distribute this DLL alongside your program, but if you do your source code must be made available.

To avoid having to release your source code, you need to remove any POSIX function calls (e.g. fork), compile using MinGW and then use cygcheck to ensure that your software no longer links against the cygwin1.dll. Or you can pay RedHat lots of money for an opt-out on releasing your code.

cygcheck has similar functionality to ldd (Linux) and otool -L (macOS).

Assertions

The debug-only macro assert is available in assert.h.

Embedded C

  • Declaring a variable as const will cause it to be stored in the program code space rather than the limited variable storage space (e.g. RAM).
  • Use the volatile keyword for pointers to memory-mapped registers, and global variables that are shared between threads.

When laying out structs, order members in descending order of size. For example:

struct abc
{
  char a; /* 1 byte */
  short b; /* 2 bytes */
  char c[5]; /* 5 bytes */
};

should be restructured as:

struct abc
{
  char c[5]; /* 5 bytes */
  short b; /* 2 bytes */
  char a; /* 1 byte */
};

Links