C++


C++ How to make cout not use scientific notation

To force cout to print numbers exactly as they are and prevent it from using the scientific notation, we can use the std::fixed I/O manipulator as follows

#include <iostream>

using namespace std;

int main()
{
    std::cout << "The number 0.0001 in fixed:      " << std::fixed << 0.0001 << endl
              << "The number 0.0001 in default:    " << std::defaultfloat << 0.0001 << endl;

    std::cout << "The number 1000000000.0 in fixed:      " << std::fixed << 1000000000.0 << endl
              << "The number 1000000000.0 in default:    " << std::defaultfloat << 1000000000.0 << endl;
return 0;
}

Output

The number 0.0001 in fixed:      0.000100
The number 0.0001 in default:    0.0001
The number 1000000000.0 in fixed:      1000000000.000000
The number 1000000000.0 in default:    1e+09
Advertisements

C++: Simplified version of ‘Friends with benefits’ demonstrating friend classes

A friend class in C++ can access the private and protected members of the class in which it is declared as a friend.

Friendship may allow a class to be better encapsulated by granting per-class access to parts of its API that would otherwise have to be public.[2] This increased encapsulation comes at the cost of tighter coupling due to interdependency between the classes.

Properties

  • Friendships are not symmetric – if class A is a friend of class B, class B is not automatically a friend of class A.
  • Friendships are not transitive – if class A is a friend of class B, and class B is a friend of class C, class A is not automatically a friend of class C.
  • Friendships are not inherited – if class Base is a friend of class X, subclass Derived is not automatically a friend of class X; and if class X is a friend of class Base, class X is not automatically a friend of subclass Derived.

From Wikipedia: https://en.wikipedia.org/wiki/Friend_class

In the following example we assign both the Man to be a friend of the Woman and the Woman to be a friend of the Man in order to allow both parties to access the private members of the other.

#include <iostream>
using namespace std;

class Man;

class Woman {
  friend class Man;

public:
  void touch(Man man);
private:
  void * body;
};

class Man {
  friend class Woman;

public:
  void touch(Woman woman);
private:
  void * body;
};

void Woman::touch(Man man) {
  void * other = man.body;
}

void Man::touch(Woman woman) {
  void * other = woman.body;
}

int main() {
  Man man;
  Woman woman;

  man.touch(woman);
  woman.touch(man);
  return 0;
}

C++: “undefined reference to” templated class function

In case you have a project where you use a templated class that is split in its own header (.h) and source (.cpp) files, if you compile the class, into an object file (.o), separately from the code that uses it, you will get the undefined reference to error at linking.

Lets assume we have Stack.cpp and Stack.h which define a templated stack using vectors. And main.cpp that uses this class after including Stack.h.

If you try to compile these files as mentioned above, one by one, later you will get a linking error saying undefined reference to for the methods of the class.

The code in the template is not sufficient to instruct the compiler to produce the methods that are needed by main.cpp (e.g. Stack<int>::push(...) and Stack<string>::push(...)) as the compiler does not know, while compiling Stack.cpp by itself, the data types it should provide support for.

The reason it allows you to compile these incomplete objects is the following:

  • main.cpp: the compiler will implicitly instantiate the template classes Stack<int> and Stack<string> because those particular instantiations are requested in main.cpp. Since the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp (particularly Stack.h), the compiler will not include complete versions of those functions in main.o and it will expect to find them in another object during linking.
  • Stack.cpp: the compiler won’t compile the instantiations of Stack<int> and Stack<string> neither as there are no implicit or explicit instantiations of them in Stack.cpp nor Stack.h.

So in the end, neither of the .o files contain the actual implementations of Stack<int> and Stack<string> and the linking fails.

Solutions

Solution 1 : Explicitly instantiate the template

At the end of Stack.cpp, you can explicitly instantiate all needed templates.
In our example we would add:

template class Stack<int>;
template class Stack<std::string>;

This will ensure that, when the compiler is compiling Stack.cpp that it will explicitly compile all the code needed for the Stack<int> and Stack<std::string> classes.

Using this method, you should ensure that all the of the implementation is placed into one .cpp file and that the explicit instantation is placed after the definition of all the functions (for example, at the end of the file).

A problem with this method is that it forces you to update the Stack.cpp file each time you want to add support for a new data type (or remove one).

Solution 2 : Move the implementation code into the header file

Move all the source code of Stack.cpp to Stack.h, and then delete Stack.cpp. Using this method you do not need to manually instantiate all possible data types that are needed and thus you do not need to modify code of the class. As a side-effect, if you use the header file in many other source files, it will compile the functions of the header file in each source. This can make compilation slower but it will not create any compilation/linking problems, as the linker will ignore the duplicate implementations.

Solution 3 : Move the implementation code into a new header file and include it in the original header file

Rename Stack.cpp to Stack_impl.h, and then include Stack_impl.h from Stack.h to keep the implementation in a separate file from the declaration. This method will behave exactly like Solution 2.


How does the expression, “*pointer++” evaluate?

*pointer++ will increment the position of the pointer first but it will return the value that was pointed before the position of the pointer changed.

*pointer++ is equivalent to *(pointer++). This happens because the postfix ++ and -- operators have higher precedence than the indirection (dereference).
You can read more about the precedence order at this very helpful article at Wikipedia: https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence

To increment the value pointed to by pointer, use (*pointer)++.

To increment the position of the pointer and return the value that is pointed after the position of the pointer changed use *++pointer.

Examples

The following example will increment the position of the pointer but return the value that was originally pointed.
By the end of the following block, pointer will point to position 1 and the value variable will have the value 11.

const unsigned int values[] = {11, 12, 14, 18};
const unsigned int *pointer = values;
const unsigned int value = *pointer++;

The following example will increment the position of the pointer and return the value that the new position is pointing to.
By the end of the following block, pointer will point to position 1 and the value variable will have the value 12.

const unsigned int values[] = {11, 12, 14, 18};
const unsigned int *pointer = values;
const unsigned int value = *++pointer;


C/C++: A small tip for freeing dynamic memory

Taking into account the behavior of the free() function, it is a good practice to set your pointer to NULL right after you free it.

By doing so, you can rest assured that in case you accidentally call free() more than one times on the same variable (with no reallocation or reassignment in between), then no bad side-effects will happen (besides any logical issues that your code might be dealing with).

You can include free() from malloc.h and it will have the following signature extern void free(void *__ptr);.

Description of operation:

Free a block allocated by malloc, realloc or calloc.
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc(), or realloc().  Otherwise, if free(ptr) has  already been called before, undefined behavior occurs.  If ptr is NULL, no operation is performed.

Working examples:

#include <stdio.h>
#include <malloc.h>

int main()
{
  printf("Hello, World!\n");

  void * c = malloc (sizeof(char) * 10);

  free(c);
  c = NULL;
  free(c);

  return 0;
}

#include <iostream>

int main()
{
  std::cout << "Hello, World!" << std::endl;

  void * c = malloc (sizeof(char) * 10);

  free(c);
  c = NULL;
  free(c);

  return 0;
}


asn1c: Generating code using ‘Automatic Tags’ and negative value as default value creates invalid function names

The following post is for the https://lionet.info/asn1c/ (repository: https://github.com/vlm/asn1c/)

When compiling the following ASN.1 data structure

GeographyModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN

    Coordinates ::= SEQUENCE
    {
        -- latitude from -90 till 90 degrees --
        latitude INTEGER(-9000000..9000000) DEFAULT -8000000,
        -- longitude from -180 till 179.99999 degrees, worst precision 1.1132m at equator --
        longitude INTEGER(-18000000..17999999) DEFAULT -12000000
    }

END

the use of both the AUTOMATIC TAGS option and the use of a negative value -8000000 in the position of the default value causes asn1c to create invalid function names in the Coordinates object.

For example, the above ASN.1 syntax will produce the following invalid function name int asn_DFL_2_set_-800000(int set_value, void **sptr).

Compilation command for asn1c

From folder asn1c_gps/asn1 we used the following command:

/home/developer/asn1c/asn1c/asn1c -pdu=auto -S /home/developer/asn1c/skeletons/ -fcompound-names -gen-PER ../geography.asn1

Version of asn1c

'ASN.1 Compiler, v0.9.28'

Example

Full example code demonstrating the bug can be found here ( asn1c_gps - Full example - Demonstrating Bug (151 downloads) ).

If you want to use the code and see that all other operations are fine, replace _- with _minus_ in the file Coordinates.c and the code will become valid and usable.

After you perform the above change, you can use the code in main.cpp to see the our cycle of execution that encodes and decodes an object.


asn1c: Decoding an OCTET STRING with lower bound limit on its size fails for uper_decode()

The following post is for the https://lionet.info/asn1c/ (repository: https://github.com/vlm/asn1c/)

Hello guys,

I’ve noticed that when I set a lower bound limit on the size of an octet string, it fails to decode it.
To reproduce this scenario I created a small but full example that is located here( asn1c_image - Full example - Demonstrating Bug (256 downloads) ).

The example( asn1c_image - Full example - Demonstrating Bug (256 downloads) ) is an application that uses the code generated by asn1c and has the following behavior:

  1. It will read a name of a file from the command line
  2. read the file to memory
  3. convert it to an octet string using OCTET_STRING_fromBuf()
  4. encode it to an ASN.1 structure using uper_encode_to_new_buffer(), after asn_check_constraints() succeeds
  5. save the encoded data to a file for debugging (same folder as the original file)
  6. decode the buffer from memory using uper_decode()
  7. save the decoded data to a file (same folder as the original file)

Methodology

To create/view the bug use this ASN1 data structure as input to the asn1c compiler:

ImagesModule DEFINITIONS ::= BEGIN

 Image ::= SEQUENCE
 {
  data OCTET STRING SIZE (40..81920)
 }

END

To hide the bug, use:

ImagesModule DEFINITIONS ::= BEGIN

 Image ::= SEQUENCE
 {
  data OCTET STRING SIZE (0..81920)
 }

END

The only difference between the two versions is the use of a lower limit constraint on the size of the OCTET string.

Compilation command for asn1c

From folder asn1c_image/asn1 we used the following command:

/home/developer/asn1c/asn1c/asn1c -pdu=auto -S /home/developer/asn1c/skeletons/ -fcompound-names -gen-PER ../images.asn1

Version of asn1c

'ASN.1 Compiler, v0.9.28'

Samples

Inside the archive, there are two files [test_01.png, bad_data.bin].

  • test_01.png is larger than 80K so it should always fail.
  • bad_data.bin fails only when there is a lower bound limit on the size

asn1c_image - Full example - Demonstrating Bug (256 downloads)


C/C++: Full example of reading a whole binary file to buffer

The following example will read a binary in full and store it to a buffer in memory.

Read binary file to memory full example source code (compressed) (182 downloads)

We used the custom structure binary_data_t to store the data information.
This structure stores the pointer to the data and their size.

struct binary_data_t {
  long size;
  void *data;
};

In main.cpp we performed three tests

  1. Reading a file that exists and is not empty
  2. Reading a non-existing file
  3. Reading an empty file

Read binary file to memory full example source code (compressed) (182 downloads)

file_helpers.h

#ifndef GM_S_LITTLE_HELPERS_FILE_HELPERS_H
#define GM_S_LITTLE_HELPERS_FILE_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct binary_data_t binary_data_t;
struct binary_data_t {
  long size;
  void *data;
};

binary_data_t * read_file(const char *filename);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_FILE_HELPERS_H

file_helpers.c

#include <stdio.h>
#include <malloc.h>
#include "file_helpers.h"


//Returns a binary_data_t structure if reading the file was OK.
//In case of an error it always returns NULL.
binary_data_t *read_file(const char *filename) {

  //Allocated our binary data structure
  binary_data_t *binary_data = malloc(sizeof(binary_data_t));
  if (binary_data != NULL) {

    binary_data->size = 0;
    void *buffer = NULL;
    long position;
    //Open the file for reading in binary mode
    FILE *fIn = fopen(filename, "rb");

    if (fIn != NULL) {
      //Go to the end of the file
      const int fseek_end_value = fseek(fIn, 0, SEEK_END);
      if (fseek_end_value != -1) {

        //Get the current position in the file (in bytes)
        position = ftell(fIn);
        if (position != -1) {

          //Go back to the beginning of the file
          const int fseek_set_value = fseek(fIn, 0, SEEK_SET);
          if (fseek_set_value != -1) {

            //Allocate enough space to read the whole file
            buffer = malloc(position);
            if (buffer != NULL) {

              //Read the whole file to buffer
              const long size = fread(buffer, 1, position, fIn);

              if (size == position) {
                binary_data->size = position;
                binary_data->data = buffer;

                fclose(fIn);
                return binary_data;
              }
              free(buffer);
            }
          }
        }
      }
      fclose(fIn);
    }
    free(binary_data);
  }
  return NULL;
}

main.cpp

#include <iostream>
#include "file_helpers.h"

int main(int argc, char *argv[]) {

  //Testing a non-zero sized file
  //read_file() will return a binary_data_t where size will be non zero
  binary_data_t *binary_data_non_zero = read_file(argv[0]);
  //Testing for a non-existing file
  //read_file() will return a NULL pointer
  binary_data_t *binary_data_not_existing = read_file("some file that does not exist...");
  const char * filename = "/tmp/some_empty_file";
  //Creating an empty file
  FILE * fout = fopen(filename, "w");
  fclose(fout);
  //Testing for an empty file
  //read_file() will return a binary_data_t where size will be zero
  binary_data_t *binary_data_empty = read_file(filename);

  return EXIT_SUCCESS;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.6)
project(GM_s_Little_Helpers)

set(CMAKE_CXX_STANDARD 11)

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

set(SOURCE_FILES main.cpp file_helpers.c file_helpers.h)
add_executable(GM_s_Little_Helpers ${SOURCE_FILES})

target_link_libraries(GM_s_Little_Helpers)

Read binary file to memory full example source code (compressed) (182 downloads)


asn1c: Full working example of ASN.1 in C/C++

The following project demonstrates a full working example of encoding and decoding ASN.1 structures using the asn1c compiler of http://lionet.info/asn1c/

In this project we assumed that we have to encode a set of geometric elements, including:

  • A rectangle that is composed by its height and its width
  • A rectangular cuboid that it is composed by a rectangle and a depth parameter
  • A list of rectangular cuboids that has no limit on how many elements to add to it
  • A list of rectangular cuboids that must have at least one element and at most three
  • We assume that all parameters should be positive integer values

ASN.1 C Full Example (compressed) (557 downloads)

Following is our ASN.1 syntax to describe the above elements:

Geometry.asn1

GeometryModule DEFINITIONS ::= BEGIN

Rectangle ::= SEQUENCE {
    height INTEGER (0..MAX),
    width INTEGER (0..MAX)
}

RectangularCuboid ::= SEQUENCE {
    depth INTEGER (0..MAX),
    rectangle Rectangle
}

UnlimitedRectangularCuboids ::= SEQUENCE OF RectangularCuboid

LimitedRectangularCuboids ::= SEQUENCE SIZE(1..3) OF RectangularCuboid

END

Inside the directory where our source is located, we created folder called geometryASN.
From that folder we executed the following command to generate the c code that is needed for our C/C++ source code to operate:

asn1c -fcompound-names -gen-PER ../Geometry.asn1

Following is our C source code that creates new ANS.1 elements, encodes them, decodes them and verifies that all limitations and constraints were met.

ASN.1 C Full Example (compressed) (557 downloads)

main.cpp

//From the folder geometryASN, to convert the ASN1 to c execute the following
// asn1c -fcompound-names -gen-PER ../Geometry.asn1
#include <iostream>
#include "geometryASN/Rectangle.h"
#include "geometryASN/RectangularCuboid.h"
#include "geometryASN/LimitedRectangularCuboids.h"
#include "geometryASN/UnlimitedRectangularCuboids.h"

bool validate_constraints(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr) {

  char error_buffer[128];
  size_t error_length = sizeof(error_buffer);
  const int return_value = asn_check_constraints(type_descriptor, struct_ptr, error_buffer, &error_length);

  if (return_value) {
    perror("asn_check_constraints() failed");
  }
  return (return_value == 0);
}

void *encode_and_decode_object(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr) {

  //First we validate that our object meets the expected constraints
  if (validate_constraints(type_descriptor, struct_ptr)) {
    void *buffer;
    asn_per_constraints_s *constraints = NULL;
    //Then, we encode the object to ASN.1 and assign the data to a buffer in memory
    const ssize_t ec = uper_encode_to_new_buffer(type_descriptor, constraints, struct_ptr, &buffer);
    if (ec == -1) {
      perror("uper_encode_to_new_buffer() failed");
    } else {
      //ASN.1 encoded object is not in the buffer variable and it is available for you to use.
      //Finally, since the encoding process went fine, we decode the data to verify with our own eyes that the process went smoothly
      void *decoded_object = 0;
      const asn_dec_rval_t rval = uper_decode(0, type_descriptor, &decoded_object, buffer, (size_t) ec, 0, 0);
      free(buffer);
      if (rval.code != RC_OK) {
        perror("uper_decode() failed");
        fprintf(stderr, "Broken encoding at byte %ld\n", rval.consumed);
      } else {
        return decoded_object;
      }
    }
  }
  return NULL;
}

int main(int argc, char *argv[]) {

  //Scenario A: We test basic encoding and decoding on a Rectangle.
  {
    //First we create a rectangle and then we encode it
    Rectangle_t *rectangle = (Rectangle_t *) calloc(1, sizeof(Rectangle_t));
    if (rectangle == NULL) {
      perror("calloc() failed");
      exit(EXIT_FAILURE);
    }
    rectangle->height = 10;
    rectangle->width = 150;

    Rectangle_t *decoded_rectangle = (Rectangle_t *) encode_and_decode_object(&asn_DEF_Rectangle, rectangle);

    if (decoded_rectangle != NULL) {
      if (rectangle->height != decoded_rectangle->height || rectangle->width != decoded_rectangle->width) {
        perror("uper_decode() failed. Wrong values found after decoding");
        ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
        ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
        exit(EXIT_FAILURE);
      }
    }
    ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
    ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
  }

  //Scenario B: We test basic encoding and decoding on a Rectangle.
  //We will provide a value that is out of the constraints area to force the test to fail.
  {
    //First we create a rectangle and then we encode it
    Rectangle_t *rectangle = (Rectangle_t *) calloc(1, sizeof(Rectangle_t));
    if (rectangle == NULL) {
      perror("calloc() failed");
      exit(EXIT_FAILURE);
    }
    rectangle->height = -10;
    rectangle->width = 150;

    Rectangle_t *decoded_rectangle = (Rectangle_t *) encode_and_decode_object(&asn_DEF_Rectangle, rectangle);

    if (decoded_rectangle != NULL) {
      perror("This test should have failed due to the constaint on the range of the valid values.");
      ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
      ASN_STRUCT_FREE(asn_DEF_Rectangle, decoded_rectangle);
      exit(EXIT_FAILURE);
    }
    ASN_STRUCT_FREE(asn_DEF_Rectangle, rectangle);
  }

  //Scenario C: We test basic encoding and decoding on a Rectangular Cuboid.
  {
    //First we create a rectangular cuboid and then we encode it
    RectangularCuboid_t *rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t));
    if (rectangular_cuboid == NULL) {
      perror("calloc() failed");
      exit(EXIT_FAILURE);
    }
    rectangular_cuboid->depth = 27;
    rectangular_cuboid->rectangle.height = 10;
    rectangular_cuboid->rectangle.width = 150;

    RectangularCuboid_t *decoded_rectangular_cuboid = (RectangularCuboid_t *) encode_and_decode_object(
        &asn_DEF_RectangularCuboid, rectangular_cuboid);

    if (decoded_rectangular_cuboid != NULL) {
      if (rectangular_cuboid->rectangle.height != decoded_rectangular_cuboid->rectangle.height
          || rectangular_cuboid->rectangle.width != decoded_rectangular_cuboid->rectangle.width
          || rectangular_cuboid->depth != decoded_rectangular_cuboid->depth) {
        perror("uper_decode() failed. Wrong values found after decoding");
        ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, rectangular_cuboid);
        ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, decoded_rectangular_cuboid);
        exit(EXIT_FAILURE);
      }
    }
    ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, rectangular_cuboid);
    ASN_STRUCT_FREE(asn_DEF_RectangularCuboid, decoded_rectangular_cuboid);
  }

  //Scenario D: We will create an array of elements that has no limitation on its size.
  {
    UnlimitedRectangularCuboids_t *unlimited_rectangular_cuboids = (UnlimitedRectangularCuboids_t *) calloc(1,
                                                                                                            sizeof(UnlimitedRectangularCuboids_t));
    if (unlimited_rectangular_cuboids == NULL) {
      perror("calloc() failed");
      exit(EXIT_FAILURE);
    }

    int i;
    for (i = 0; i < 10; i++) {       RectangularCuboid_t *tmp_rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t));       if (tmp_rectangular_cuboid == NULL) {         perror("calloc() failed");         exit(EXIT_FAILURE);       }       tmp_rectangular_cuboid->depth = i;
      tmp_rectangular_cuboid->rectangle.height = i * 11;
      tmp_rectangular_cuboid->rectangle.width = i * 101;

      const int result = asn_set_add(unlimited_rectangular_cuboids, tmp_rectangular_cuboid);
      if (result != 0) {
        perror("asn_set_add() failed");
        ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
        exit(EXIT_FAILURE);
      }
    }

    UnlimitedRectangularCuboids_t *decoded_unlimited_rectangular_cuboids = (UnlimitedRectangularCuboids_t *) encode_and_decode_object(
        &asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);

    if (decoded_unlimited_rectangular_cuboids != NULL) {
      for (i = 0; i < decoded_unlimited_rectangular_cuboids->list.count; i++) {
        RectangularCuboid_t *tmp_rectangular_cuboid = decoded_unlimited_rectangular_cuboids->list.array[i];
        if (tmp_rectangular_cuboid->rectangle.height != i * 11
            || tmp_rectangular_cuboid->rectangle.width != i * 101
            || tmp_rectangular_cuboid->depth != i) {
          perror("uper_decode() failed. Wrong values found after decoding");
          ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
          ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, decoded_unlimited_rectangular_cuboids);
          exit(EXIT_FAILURE);
        }
      }
    }
    ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, unlimited_rectangular_cuboids);
    ASN_STRUCT_FREE(asn_DEF_UnlimitedRectangularCuboids, decoded_unlimited_rectangular_cuboids);
  }

  //Scenario E: We will create an array of elements that has a limitation on how many elements it can accept.
  //We will add more elements than expected and we expect the encoding to fail.
  {
    LimitedRectangularCuboids_t *limited_rectangular_cuboids = (LimitedRectangularCuboids_t *) calloc(1,
                                                                                                      sizeof(LimitedRectangularCuboids_t));
    if (limited_rectangular_cuboids == NULL) {
      perror("calloc() failed");
      exit(EXIT_FAILURE);
    }

    int i;
    for (i = 0; i < 10; i++) {       RectangularCuboid_t *tmp_rectangular_cuboid = (RectangularCuboid_t *) calloc(1, sizeof(RectangularCuboid_t));       if (tmp_rectangular_cuboid == NULL) {         perror("calloc() failed");         exit(EXIT_FAILURE);       }       tmp_rectangular_cuboid->depth = i;
      tmp_rectangular_cuboid->rectangle.height = i * 11;
      tmp_rectangular_cuboid->rectangle.width = i * 101;

      const int result = asn_set_add(limited_rectangular_cuboids, tmp_rectangular_cuboid);
      if (result != 0) {
        perror("asn_set_add() failed");
        ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
        exit(EXIT_FAILURE);
      }
    }

    LimitedRectangularCuboids_t *decoded_limited_rectangular_cuboids = (LimitedRectangularCuboids_t *) encode_and_decode_object(
        &asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);

    if (decoded_limited_rectangular_cuboids != NULL) {
      perror("This test should have failed due to limitation on the size of the list.");
      ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
      ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, decoded_limited_rectangular_cuboids);
      exit(EXIT_FAILURE);
    }
    ASN_STRUCT_FREE(asn_DEF_LimitedRectangularCuboids, limited_rectangular_cuboids);
  }

  printf ("All tests were successful\n");
  return EXIT_SUCCESS;
}

ASN.1 C Full Example (compressed) (557 downloads)


C/C++: Full example using a linked list with custom struct

The following code is an example that presents some basic functionality on simply linked lists. Specifically, it presents how to add an element to an empty list and then how to add more elements either to the start (prepend) or to the end (append) of the list.

list_helpers.c (compressed) (122 downloads)

We assume that our structure holds an integer and a dynamically created string, which we free after pop.

list_helpers.c (compressed) (122 downloads)

 

Source file (list_helpers.c)

#include <malloc.h>
#include "list_helpers.h"

void append(node_t **head, element_t *element) {

  struct node_t *new = malloc(sizeof(node_t));
  new->element = element;
  new->next = NULL;

  if (*head == NULL) {
    *head = new;
    return;
  }

  struct node_t *current = *head;

  while (current->next != NULL) {
    current = current->next;
  }

  current->next = new;
  return;
}

void prepend(node_t **head, element_t *element) {
  struct node_t *new = malloc(sizeof(node_t));

  new->element = element;
  new->next = *head;
  *head = new;
}

element_t *pop(node_t **head) {

  node_t *next = NULL;

  if (*head == NULL) {
    return NULL;
  }

  next = (*head)->next;
  element_t *element = (*head)->element;
  free(*head);
  *head = next;

  return element;
}

void clear(node_t **head) {
  element_t *current = pop(head);
  while (current != NULL) {
    free(current->username);
    free(current);
    current = pop(head);
  }
}

Header file (list_helpers.h)

#ifndef GM_S_LITTLE_HELPERS_LIST_HELPERS_H
#define GM_S_LITTLE_HELPERS_LIST_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct element_t element_t;
struct element_t {
  //We add random members to the element struct for the sake of the example
  char *username;
  unsigned int server;
};

typedef struct node_t node_t;
struct node_t {
  element_t *element;
  node_t *next;
};

void append(node_t **head, element_t *element);

void prepend(node_t **head, element_t *element);

element_t *pop(node_t **head);

void clear(node_t **head);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_LIST_HELPERS_H

Usage example (main.cpp)

#include <iostream>
#include "list_helpers.h"

element_t *create_user(const unsigned int server, const char *username) {

  element_t *user = (element_t *) malloc(sizeof(element_t));
  user->server = server;

  //For the sake of the example we used snprintf.
  //Upon successful return, snprintf returns the number of characters printed (excluding the null byte used to end output to strings).
  //For that reason we add one at the end of the length.
  const int length = snprintf(NULL, 0, "%s", username) + 1;
  user->username = (char *) malloc((sizeof(char) * length));
  snprintf(user->username, (size_t) length, "%s", username);
  return user;
}

int main(int argc, char *argv[]) {

  node_t *head = NULL;

  //Add the first element to the linked list
  append(&head, create_user(10, "xeirwn"));

  //Add the second element to the end of the linked list
  append(&head, create_user(12, "test"));

  //Add the third element to the end of the linked list
  append(&head, create_user(14, "banana"));

  //Add the fourth element to the beginning of the linked list
  prepend(&head, create_user(8, "apple"));

  //Popping each one to process it and then free it
  //Clearing the list
  element_t *current = pop(&head);
  while (current != NULL) {

    printf("%s\t%u\n", current->username, current->server);
    free(current->username);
    free(current);
    current = pop(&head);
  }

  //Safely clear the list. In this specific scenario it will have 0 side effects as the list was cleared above
  clear(&head);
  return 0;
}
list_helpers.c (compressed) (122 downloads)