C programming notes

From Wiki at Neela Nurseries
Jump to: navigation, search

programming notes   ::   coding style

^ Overview

This page to hold notes and links to C programming resources and reference materials. A language standards document is available at https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf.

A good tool to aid writing C code is the indexing utility known as `ctags`:


^ Data Type and Limits

See the following C library headers for important data type definitions, such as the definition of `uint32_t` and CHAR_BIT.

  • zephyr/lib/libc/minimal/include/stdint.h
  • zephyr/lib/libc/minimal/include/limits.h

Two important C data types worth noting include size_t and ssize_t. These are unsigned, and signed types respectively. An Ubuntu reference site which provides manual pages goes into this further:

. . . in duplicative fashion this link is referenced in this article's section on C format specifiers.

The C type `ssize_t` allows for a variable to hold both positive values and negative values, which is useful when variables are changed during function calls. This signed quality permits a function to return a valid value, and also an error code which may be encoded in the negative range of integer values.

In Zephyr RTOS 3.6.0 it appears that `size_t` is defined in a header file named stddef.h. On 2024-09-04 not able to locate this header file in Zephyr's source tree, but Zephyr source kernel_headers.h includes this file with the stanza:

 #include <stddef.h>

^ C pointer and file size types

This section provides links to C language type `off_t`, which is sometimes defined in types.h.

From Madagascar Programming Reference Manual, first a link to this documentation's node 44:

Node 43 and node 1 respectively:


^ C Qualifiers and Type Casting


^ C attributes

The language of C provides attributes for functions, for variables, for labels, for enumerations and for C data types.

C `fallthrough` Attribute, used to inform compiler not to warn about code scoped to a given case in switch statement continuing on to the next case statement. Note, C `break` statement is commonly used to control execution flow and have code of a given case complete and then skip remaining cases altogher:

C type attributes:


^ C structures

C structures can be referenced using differing syntax. To do: investigate and test following psuedo-code . . .

struct a {
   char element_a;
   size_t element_b;
};

struct a structure_a_1;

structure_a_1.element_a = 'M';
structure_a_1.element_b = 100;

printf("Test:  %c, %u\n", structure_a_1.element_a, structure_a_1.element_b);

// Note may need a C cast following assignment operator in next line:

structure_a_1 = {
   .structure_a_1.element_a = 'L';
   .structure_a_1.element_b = 8585;
}

printf("Test:  %c, %u\n", structure_a_1.element_a, structure_a_1.element_b);


^ C Macros

This section likely to grow as C macros have a development history somewhat separate from the development of C language itself, and extensive use being both powerful and prone to pitfalls.

Articles on the use of C language 'do while(0)' construct in macros. The do while(0) construct is the only C syntax which expands correctly from C macros regardless of the use of curly braces and semicolons around the given macro.

A useful macro pair, and this must be a macro pair, is the following set of defines. These defines will accept a string and put double quotes around it:

  #define MAKE_STRING_QUOTED(string) #string
  #define WRAPPER_NEEDED_TO_QUOTE_STRING(token) MAKE_STRING_QUOTED(string)

One Guy Rutenberg explains this C pre-processor pattern:

This C macro pattern is explained a number of other places as well.


The `__fallthrough()` macro appears to be a C++ macro. It may be found among Zephyr RTOS 3.4.0 source tree contents. An article on the concept of "fall through" in C switch statements:

Some larger introductions and discussions of C preprocessor and C macros are found at these four references:

1001 # https://stackoverflow.com/questions/4674480/do-whilefalse-pattern
1002 # https://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html
1003 # https://en.wikipedia.org/wiki/C_preprocessor#X-Macros
1004 # https://en.wikipedia.org/wiki/X_macro


^ C Pointers and dereference syntax

This section the beginning of references, links and personal notes on some of the most difficult and important C language constructs, often used in schedulers and RTOS implementations:

Arrays of strings and arrays of pointers to strings:

Pointers to functions, their syntax and several use cases:


^ String Versus Non-string Data

A takeaway from following Stack Exchange forum post is that C strings are null-terminated by definition. There is mention of this being a "C idiom", in other words, a string without a null byte to terminate it is not a C string.



  - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -

^ Printf Family Functions

C functions printf, snprintf and vprintf and related make use of variadic function signatures. That is, these functions accepts arbitrary arguments which they do not know at compile time. Useful infomation on C library's variadic function macros and C standard argument `stdarg.h` framework can be found via manual pages:

    $ man 3 printf
    $ man 3 stdarg

Related to this, Zephyr RTOS printk header [file https://docs.zephyrproject.org/apidoc/latest/printk_8h_source.html printk.h] calls on a macro named __printf_like(a, b).

More about C standard library variadic function support can be learned via `main va_start`.


^ C Format Specifiers

C format specifier %z -- Stackoverflow post says to use %z for size_t formatting . . .

Ubuntu site manpages mentions %z and %j are C format length specifiers . . .


^ Co-routines

Interesting article by Simon Tatham on co-routines and a couple ways of implementing them in C language; accessible good style of writing:

Quote from the article:

    <! -- not intended use for ul tag --> "Any coding standard which insists on syntactic clarity at the expense of algorithmic clarity should be rewritten."  - Simon Tatham


^ Errno dot h

Error codes for Unix and Linux operating systems, and C library based projects such as RTOS Zephyr are often defined in a header file named errno.h. Versions of this file from system to system and environment to environment often vary, leading to compatibility issues. This section a starting point to address benefits and challenges, and hopefully some answers on the challenge side of using errno.h for project error codes.

Interesting, as of 2024-07-12 a few websites are still made public via non-secure http protocol. Link to Blackberry / QNX online documentation on errno codes:

Forum posts, further posts on C error codes and errno.h:


^ __ASSERT Macro In C Programs

A good starting point article at Memfault dot com, about when and why to use ASSERT statements:


  - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -

^ conditional variables

Use of pthread_cond_t . . .


^ Simple C examples

Program 1 - use of C comma operator, a binary operator:

#include <stdio.h>
#include <stdlib.h>

// Compile with:
//
//    $ gcc -Wall main.c
//
// As of 2022-06-09 Builds with 'gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0'

int main(int argc, char *argv[])
{
    int z = 3;

    int y[(z++, (z + 1))];

    y[0] = 1;

    if ( z == y[0] ) { } 

#define SIZE_OF_160_BYTES (160)
    char lbuf[SIZE_OF_160_BYTES] = { 0 };
    snprintf(lbuf, SIZE_OF_160_BYTES, "2022-06-09 main.c test of C comma operator\narray y[] has size of %lu\n",
      sizeof(y));
    printf("%s", lbuf);

    return 0;
}


^ Serial Port Use in C

// Example 3.2 code from https://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#include <stdlib.h>                //echo "z" >> /dev/ttyS1 to provide exit()

// https://man7.org/linux/man-pages/man3/bzero.3.html
#include <strings.h>               // to provide bzero()

// https://man7.org/linux/man-pages/man2/read.2.html
// https://linux.die.net/man/3/read
#include <unistd.h>                // to provide read()


    
#define BAUDRATE B38400
//#define MODEMDEVICE "/dev/ttyS1"
#define MODEMDEVICE "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
    
volatile int STOP=FALSE; 
    
int main(void)
{
        int fd, c, res;
        struct termios oldtio,newtio;
        char buf[255];
    
    printf("Starting,\nopening serial device '%s' . . .\n", MODEMDEVICE);

        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );  
        if (fd <0) {perror(MODEMDEVICE); exit(-1); }

        tcgetattr(fd,&oldtio); /* save current port settings */

        bzero(&newtio, sizeof(newtio));
//        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
        newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR;
        newtio.c_oflag = 0;

        /* set input mode (non-canonical, no echo,...) */
        newtio.c_lflag = 0;

        newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
        newtio.c_cc[VMIN]     = 5;   /* blocking read until 5 chars received */

        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);


    printf("looping to read from serial port . . .\n");
        while (STOP==FALSE) {       /* loop for input */
          res = read(fd,buf,255);   /* returns after 5 chars have been input */
          buf[res]=0;               /* so we can printf... */
          printf(":%s:%d\n", buf, res);
          if (buf[0]=='z') STOP=TRUE;
        }
        tcsetattr(fd,TCSANOW,&oldtio);

    return 0;
}


  - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -   - - - - -

^ References


Floating point convert and notes on-line, Javascript converter: