C: Difference between revisions

From miki
Jump to navigation Jump to search
Line 172: Line 172:
;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(int)(!!(e)) }
;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(int)(!!(e)) }
#endif
#endif
</source>

=== Call a function at a given absolute address ===

Using a nice <code>typedef</code> [https://stackoverflow.com/questions/8915797/calling-a-function-through-its-address-in-memory-in-c-c/44636131#44636131 SO]:

<source lang="c">
typedef int func(void);
func* f = (func*)0xdeadbeef;
int i = f();
</source>

Avoiding the assignment:
<source lang="c">
typedef int func(void);
int i = ((func*)0xdeadbeef)();
</source>

All in one line:
<source lang="c">
int i = ((int (*)(void))0xdeadbeef)();
</source>
</source>



Revision as of 17:06, 19 June 2017

References

sudo apt-get install manpages-dev manpages-posix-dev
On this wiki

Tips

Struct Initializer

struct {
    int a;
    int b;
} s = { .a = 1, .b = 2 };

Same applies for union.

Variadic Macros

See reference here.

#define eprintf(...) fprintf (stderr, __VA_ARGS__)
/* eprintf ("%s:%d: ", input_file, lineno)
          ==>  fprintf (stderr, "%s:%d: ", input_file, lineno) */
#define eprintf(args...) fprintf (stderr, args)
#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)

An handy macro hack that counts the number of parameters passed before expansion (See [1] and [2]):

 /* The PP_NARG macro returns the number of arguments that have been
  * passed to it. This compensates for lack of __VA_NARGS__.
  * Macros written by Laurent Deniau See http://en.wikipedia.org/wiki/Variadic_macro.
  */ 

#define PP_NARG(...) \ 
         PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) 
#define PP_NARG_(...) \ 
         PP_ARG_N(__VA_ARGS__) 
#define PP_ARG_N( \ 
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ 
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ 
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ 
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ 
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ 
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ 
         _61,_62,_63,N,...) N 
#define PP_RSEQ_N() \ 
         63,62,61,60,                   \ 
         59,58,57,56,55,54,53,52,51,50, \ 
         49,48,47,46,45,44,43,42,41,40, \ 
         39,38,37,36,35,34,33,32,31,30, \ 
         29,28,27,26,25,24,23,22,21,20, \ 
         19,18,17,16,15,14,13,12,11,10, \ 
         9,8,7,6,5,4,3,2,1,0 

/* Some test cases */ 
PP_NARG(A) -> 1 
PP_NARG(A,B) -> 2 
PP_NARG(A,B,C) -> 3 
PP_NARG(A,B,C,D) -> 4 
PP_NARG(A,B,C,D,E) -> 5 
PP_NARG(1,2,3,4,5,6,7,8,9,0, 
         1,2,3,4,5,6,7,8,9,0, 
         1,2,3,4,5,6,7,8,9,0, 
         1,2,3,4,5,6,7,8,9,0, 
         1,2,3,4,5,6,7,8,9,0, 
         1,2,3,4,5,6,7,8,9,0, 
         1,2,3) -> 63

Variadic I/O Functions

See [3] for some reference information on variable functions.

The standard variadic I/O functions are:

#include <stdio.h>
#include <stdarg.h>

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

Example of use:

//This works both on win32 / linux

#include <stdio.h>
#include <stdarg.h>

void vario(const char* formatstr,...)
{
    va_list args;
    va_start(args, formatstr);

    vprintf(formatstr, args);

    va_end(args);                      /* cleanup - DON'T FORGET */
}

Note on win32:

There exists alternative functions ([4]) prefixed with a '_', such as _vprintf_p, _vfprintf_l, ...

Temporary variable names for Macro

/* UNIQ(x) creates a unique variable name that depends on the current source line as returned by __LINE__. We need
   Several intermediate macros because identifier are not expanded in macro if they are used along with # or ## in
   macro definition.

   Example:   #define SCAN_MY(var,n)   {int UNIQ(x); for(UNIQ(x)=0; UNIQ(x)<n; ++UNIQ(x)) printf(var[UNIQ(x)]);}
*/
#define UNIQ__(x,y) x ## y
#define UNIQ_(x,y)  UNIQ__(x,y)
#define UNIQ(x)     UNIQ_(x,__LINE__)

Static assertions

Static assertions are assertions that can be verified at compile time.

From Static_assertions (WP):

#define SASSERT(pred) switch(0){case 0:case pred:;}
 
SASSERT( BOOLEAN CONDITION );
static char const static_assertion[ (BOOLEAN CONDITION)
                                    ? 1 : -1
                                  ] = {'!'};

Variadic macros

From GNU CC Manual - Variadic Macros.

#define eprintf(...)     fprintf (stderr, __VA_ARGS__)       // C99 Standard
#define eprintf(args...) fprintf (stderr, args)              // GNU extension
#define eprintf(args...) fprintf (stderr, ## args)           // GNU extension

Some caveats:

#define eprintf(format,...) fprintf (stderr, format, __VA_ARGS__)

Looks more descriptive, but now at least one argument must be provided, except if compiler supports the construction (gcc, vc).

Static assert

Static assert that supports sizeof() operator: http://www.pixelbeat.org/programming/gcc/static_assert.html.

#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
/* These can't be used after statements in c89. */
#ifdef __COUNTER__
  #define STATIC_ASSERT(e,m) \
    ;enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(int)(!!(e)) }
#else
  /* This can't be used twice on the same line so ensure if using in headers
   * that the headers are not included twice (by wrapping in #ifndef...#endif)
   * Note it doesn't cause an issue when used on same line of separate modules
   * compiled with gcc -combine -fwhole-program.  */
  #define STATIC_ASSERT(e,m) \
    ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(int)(!!(e)) }
#endif

Call a function at a given absolute address

Using a nice typedef SO:

typedef int func(void);
func* f = (func*)0xdeadbeef;
int i = f();

Avoiding the assignment:

typedef int func(void);
int i = ((func*)0xdeadbeef)();

All in one line:

int i = ((int (*)(void))0xdeadbeef)();

Pits

Multiple definition of uninitialized variables

By default, gcc allow multiple definition of uninitialized variables! This is really EVIL.

Solutions:

  • Use gcc flag -fno-common to forbid that (error)
  • Use ld flag --warn-common (aka. -Wl,--warn-common in gcc) to get a warning

References:

Let's consider foo.c

int foo;

bar.c

int bar=0;

and main.c

int foo;
int bar=0;

int main(int argc, char** argv)
{
    return foo+bar;
}

We have the following:

$ gcc main.c bar.c
# /tmp/ccjIc7Is.o:(.bss+0x0): multiple definition of `bar'
# /tmp/ccFys0wm.o:(.bss+0x0): first defined here
# collect2: ld returned 1 exit status

gcc main.c foo.c
# No error !!!

gcc does not report any error for duplicate definitions of uninitialized variables. We can force it as follows:

gcc -fno-common main.c foo.c
# /tmp/ccnMOLlf.o:(.bss+0x0): multiple definition of `foo'
# /tmp/cc5YeNxE.o:(.bss+0x0): first defined here
# collect2: ld returned 1 exit status

gcc -Wl,--warn-common main.c foo.c
# /tmp/ccm9Z06a.o: warning: multiple common of `foo'
# /tmp/ccJIfrYq.o: warning: previous common is here

Undefined reference

Undefined reference with gcc although library is given

gcc -lm mymath.c -o mymath
/tmp/ccI4NbJJ.o: In function `V':
mymath.c:(.text+0x235): undefined reference to `pow'

The solution is to have the -lm at the end. Order does make a difference (at least since gcc 4.6).

gcc mymath.c -o mymath -lm

No sequence point in assignment operator

The following code is wrong [5]:

uint32_t
swaphalves(uint32_t a)
{
    a = (a >> 16) | (a << 16);
    return a;
}

There is no sequence point here, and so we don't know anything about the order of operations here. Of course the code can be easily fixed:

uint32_t
swaphalves(uint32_t a)
{
    return (a >> 16) | (a << 16);
}

More on sequence points [6], [7], [8] (! links for C++, there might be difference with C).

Strict Aliasing

See [9]

Addr-of array, &a

int a[4];
int *p;

p=&a+2;             // WRONG - ACCESS (void *)a + 2*sizeof(a)
p=a+2;              // CORRECT - ACCESS (void *)a + 2*sizeof(int)
p=&a[2];            // CORRECT
*p=1;

Libraries

P99

P99 is not a regular library but instead a set of include files that offer powerful preprocessor macros (like P99_DUPL(...), P99_NARG(...)). From the website:

P99 is not a C library in the classical sense but merely a collection of include files:

  • There is no binary library to be linked to your executable. The few functions that are provided are small wrappers that are compiled directly into your code.
  • There is nothing to configure, P99 include files should work out of the box with any conforming C99 compiler.

Debugging

See general page on Debugging.

Embedded C

Some tips to make embedded development with C.

Enum are not always int

Some compilers do not necessarily map enum types to int. The standard says it is platform-dependent. Some compiler may use (or be configured to use) the smallest date type that can hold the value of all enumerators.

To prevent strange behaviour, always enforce the enum size as follows:

typedef enum MyEnum_t {
  first     = 1,
  second    = 2,
  _forceint = 0x7FFFFFFF             // To force 32-bit (signed) enum
} MyEnum_t;

Using packed enum

Some compiler supports storing enum using the smallest data type (signed or unsigned):

Command-line options
  • On gcc, use option --short-enums or -fshort-enums:
gcc --short-enums -c file.c 
gcc -fshort-enums -c file.c
  • On clang, use option -fshort-enums:
clang -fshort-enums -c file.c
  • ARM compilers have similar options
Source code
  • gcc and alike: Use pragma __attribute__((packed))
typedef enum {a,b} __atribute__((packed)) letters;
  • VC: Support only packed structure
#pragma pack(push,1)
typedef struct {
  letters  x;
}
#pragma pack(pop)

Win32 vs Linux

Linux Win32 Comment
snprintf _snprintf deprecated, replaced by _snprintf_s but not compatible