AWS IoT Device SDK C  202009.00
SDK for connecting to AWS IoT from a device using embedded C.
Style Guide

Guide for the coding style used in this SDK.

The goal of this style guide is to encourage a readable and consistent coding style across the entire SDK.

Coding Style

The coding style used in this SDK.

The coding style aims to produce code that is readable and easy to debug. An example is provided in Example File.

General guidelines

General guidelines for library style.

  • All libraries should only use ANSI C features and standard library functions.
  • Libraries should log extensively, but exceptions are made for pure functions.
  • Code should be well-commented.
  • Only /* and */ should be used to start and end comments.
  • All comments end with a period.
  • Use of goto is discouraged.
  • Only spaces should be used for indenting. A single indent is 4 spaces. No tab characters should be used.
  • A parenthesis is usually followed by a space (see Example File).
  • Lines of code should be less than 80 characters long, although longer lines are permitted.
  • Local variables should be declared at the top of a block in the narrowest scope possible. Reducing complexity could be a valid case for breaking this guideline, so this should be done at the programmer's discretion.
  • All global variables should be declared at the top of a file.
  • Variables are always initialized.
  • A separator is placed between different sections of a file. The current separator is:
    /*-----------------------------------------------------------*/
  • All files must include the config file at the top of the file before any other includes.
  • static functions must have a declaration at the top of the file and be implemented before any application-facing functions.
  • The GNU complexity of every function should be less than 9.
  • Deviations from MISRA C:2012 coding guidelines should be documented as comments in the code.

Type guidelines

Guidelines for variable types.

  • Although not a part of the C89 standard, only fixed-width integer types should be used. Exceptions are for bool and types required by third-party APIs.
  • The default integer in the libraries should be 32 bits wide, i.e. int32_t or uint32_t.
  • Sizes and lengths should be represented with size_t.
  • Libraries may define bool macros for use with C89 compilers.

Example File

An example file that follows the coding style rules.

See Naming for how to name the functions, variables, and macros.

/*
* License header pasted here.
*/
/* Included headers are at the top of the file. The config file include is always first. */
#include "config.h"
/* Standard includes are immediately after the config file. They are sorted alphabetically.
* They use angle brackets <> around the file name. */
/* Standard includes. */
#include <assert.h>
#include <stddef.h>
#include <string.h>
/* This file defines `bool` for compatibility with C89 compilers. */
#if defined( __cplusplus ) || ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) )
#include <stdbool.h>
#elif !defined( bool ) && !defined( false ) && !defined( true )
#define bool int8_t
#define false ( int8_t ) 0
#define true ( int8_t ) 1
#endif
/* Library internal headers are included next. They use quotes "" around the file name. */
/* Library internal include. */
#include "private/library_internal.h"
/* Error handling include (include only when needed). */
#include "private/error.h"
/* Library application-facing headers are included last. They use quotes "" around the file name. */
/* Library include. */
#include "library.h"
/*-----------------------------------------------------------*/
/* Defined constants follow the included headers. */
/* When possible, parentheses () should be placed around constant values and a type
* should be specified. */
#define LIBRARY_CONSTANT ( ( int32_t ) 10 )
#define LIBRARY_FUNCTION_MACRO( argument ) \ /* Line continuators are right-aligned. */
{
\ /* Function-like macros are surrounded by curly braces {}. */
macro_body( ( argument ) );
\ /* Parentheses surround macro arguments for MISRA 20.7 */
}
/*-----------------------------------------------------------*/
/* Library typedefs follow the defined constants. */
/* Forward declarations are used only when necessary. They are placed before all
* other typedefs. */
typedef int32_t type_t;
typedef struct structType
{
int32_t member;
/* As usage of unions violates MISRA rule 19.2, we must document our usage
* and justification. Unions are used here to reduce the size of this struct. */
union /* Anonymous structs/unions are permitted only inside of other structs. */
{
int8_t a[ 4 ];
int32_t b;
};
} structType_t;
/*-----------------------------------------------------------*/
/* Declarations of static and extern functions follow the typedefs. */
static bool libraryStaticFunction( void * pArgument,
size_t argumentLength );
/* External function declarations should be used sparingly (using an internal
* header file to declare functions is preferred). */
extern int32_t Library_ExternalFunction( void * pArgument );
/*-----------------------------------------------------------*/
/* Declarations of global variables follow the static and extern function
* declarations. Global variables are permitted, but should be avoided when
* possible. */
/* Global variables are always initialized. */
static int globalVariable = 0;
static int pGlobalArray[ LIBRARY_CONSTANT ] = { 0 };
/*-----------------------------------------------------------*/
/* Implementations of static functions follow the global variable declarations. */
static bool libraryStaticFunction( void * pArgument,
size_t argumentLength )
{
int32_t * pLocalPointer = ( int32_t * ) pArgument;
bool status = true;
/* All functions make generous use of the logging library. */
LogInfo( "Performing calculation..." );
if( ( pArgument == NULL ) || ( argumentLength == 0 ) ) /* Note the parentheses and spacing in if statements */
{
LogError( "Bad parameters." );
/* Local variable instead of a goto for error handling. */
status = false;
}
else /* Note an else clause is used instead of goto for error handling */
{
/* Local variables should be declared at the top of a block in the narrowest scope possible. */
int32_t localVariable = 0;
size_t i;
for( i = 0; i < argumentLength; i++ ) /* Note the spacing in the for loop. */
{
localVariable += Library_ExternalFunction( pArgument );
LogDebug( "Current value is %d.", ( int ) localVariable );
}
if( localVariable < 0 )
{
LogWarn( "Failed to calculate positive value." );
}
LogInfo( "Calculation done." );
}
return status;
}
/* A separator is placed between all function implementations. */
/*-----------------------------------------------------------*/
/* Implementations of application-facing functions are at the bottom of the file. */
bool Library_ApplicationFunction( void ) /* Functions with no arguments have void in their argument list. */
{
LIBRARY_FUNCTION_MACRO( globalArray );
return true;
}
/* Separator and newline at end of file */
/*-----------------------------------------------------------*/

Naming

Naming convention used in this SDK.

The naming convention aims to differentiate this SDK's files, variables, and functions to avoid name collisions. In general:

  • The first characters of all publicly visible names should identify the name as part of this SDK.
    Example: For general-purpose libraries (such as MQTT), names start with <library-name>_ (i.e. MQTT_ for the MQTT API).
  • Words in names should be ordered with the most general word first and the most specific word last.
    Example: core_mqtt_serializer.c identifies a file as part of the general MQTT library. MQTT_Connect identifies a public-facing function of the general MQTT library.
  • Names should avoid using abbreviations.

Defined constants and enum values

Naming convention for constants set using preprocessor #define and enum values.

This table contains the formats for the names of the most common SDK defined constant and enum values. It is not intended to be comprehensive. Bold text indicates a variable but required part of the defined constant and enum value's name.

Format Applies to Example
LibraryDescription Defined constants and enum values in application-facing library header files MQTTSuccess (core_mqtt_lightweight.h)
LIBRARY_DESCRIPTION Defined constants and enum values in demos and tests MQTT_EXAMPLE_TOPIC
DESCRIPTION Internal constants and enum values
No AWS_ prefix for internal names in AWS-specific libraries
ROOT_CA_CERT_PATH

Files

Naming convention for files.

This table contains the formats for the names of the most common SDK files. It is not intended to be comprehensive. Bold text indicates a variable but required part of the file's name.

Format Applies to Example
library_description.extension General library file core_mqtt_serializer.c
library_internal.h Internal library header core_mqtt_internal.h
library_demo_description.c Library demo source mqtt_demo_plaintext.c
library_description_utest.c
library_description_system_test.c
Library test source core_mqtt_utest.c
mqtt_system_test.c

File names contain only lowercase letters and underscores. All file names should be named according to their purpose. For example:

  • core_mqtt_state.c: A file in the MQTT library that handles state of MQTT PUBLISH packet deliveries.
  • mqtt_demo_plaintext.c: A file in the demos for the MQTT library that communicates over a plaintext channel.
  • core_mqtt_utest.c: A file in the Tests for the MQTT library. Since the tests currently only run on POSIX systems, test file names do not use the _posix suffix.

Library file names should use one or two words to describe the functions implemented in that file. For example:

  • core_mqtt_serializer.c: Implements the MQTT library's packet serialization and deserialization functions.
  • clock_posix.c: Implements the platform clock component for POSIX systems.

Declarations of internal functions, structures, macros, etc. of a library should be placed in a header file with an _internal suffix. The _internal header file should go in the source/include/private directory. For example:

  • core_mqtt_internal.h: Declares the MQTT library's internal functions, structures, macros, etc.

File names for demos should begin with library_demo_. Unit tests must start with library_ and end with _utest. System tests must start with library_ and end with _system_test. The names should then specify the library being demoed or tested. For example, the files names of the MQTT library's demos start with mqtt_demo_. Additionally, test file names should describe what tests are implemented in the file, such as mqtt_demo_mutual_auth.c for a file containing a demo that mutually authenticates over TLS with an MQTT broker.

Functions (and function-like macros)

Naming convention of functions and function-like macros.

This table contains the formats for the names of the most common SDK functions. It is not intended to be comprehensive. Bold text indicates a variable but required part of the function's name.

Format Applies to Example
Library_Description Externally-visible library function MQTT_Publish
description static function (never uses Aws prefix) sendPublish
eventCallback
test_Library_accessedFunction_Description Test access function test_MQTT_ProcessLoop_Timer_Overflow

Externally visible (i.e. not static) functions are UpperCamelCased. Function names should then specify their library name, followed by an underscore, followed by a brief description of what the function does. For example:

  • MQTT_SerializePublish: This function is part of the public MQTT API. It serializes an MQTT PUBLISH packet into a buffer.

Functions not visible outside their source file (i.e. static functions) have names that are lowerCamelCased. These function names do not contain the library name or Aws. For example:

  • receiveSingleIteration: A static function in core_mqtt.c.

Types

Naming conventions of library typedef types.

This table contains the formats for the names of the most common SDK types. It is not intended to be comprehensive. Bold text indicates a variable but required part of the type's name.

Format Applies to Example
LibraryDescription_t General types in application-facing library header files MQTTStatus_t (core_mqtt.h)

Types intended for use in applications are UpperCamelCased. The names end with _t. Parameter structures should indicate their associated function: for example, MQTTPublishInfo_t is passed as a parameter to MQTT_Publish.

Types intended for internal library use defined in a header file are lowerCamelCased. The names must start with the library name and end with _t. Internal types defined in a library source file must end with _t and not include the library name.

struct typedefs should always be named along with the typedef. The struct name should be identical to the typedef name, but without the _t suffix. For example:

typedef struct LibraryStruct
{
int32_t member;
} LibraryStruct_t;
typedef struct libraryInternalStruct
{
int32_t member;
} libraryInternalStruct_t;

A struct may contain union members, but its usage must be documented as it violates MISRA rule 19.2.

Variables

Naming conventions of variables.

This table contains the formats for the names of the most common SDK variables. It is not intended to be comprehensive. Bold text indicates a variable but required part of the variable's name.

Format Applies to Example
variableDescription General local variable startTime
pVariableDescription Variable pointers and arrays (including strings) pSubscriptionList

Local variable names are lowerCamelCased and consist only of a description of the variable. Names like i or j are acceptable for loop counters, but all other variables should have a descriptive name.

Global variables that are static consist of only the description in lowerCamelCase. Global variables that are not static consist of the library name and the description in UpperCamelCase.

All pointers, arrays, and strings (both global and local) start with p.

LogInfo
#define LogInfo(message)
Definition of logging interface macro that logs messages at the "Info" level, when info level logging...
Definition: logging_stack.h:160
LogDebug
#define LogDebug(message)
Definition of logging interface macro that logs messages at the "Debug" level, when debug level loggi...
Definition: logging_stack.h:151
LogWarn
#define LogWarn(message)
Definition of logging interface macro that logs messages at the "Warning" level, when warning level l...
Definition: logging_stack.h:169
LogError
#define LogError(message)
Definition of logging interface macro that logs messages at the "Error" level, when error level loggi...
Definition: logging_stack.h:178