C


C: Read a floating number that might be in the format of scientific notation

This code will read a floating number that might be in the format of scientific notation from the keyboard.
Then it will print out the number with the scientific notation and without it.

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

int main() {
  printf("This code will read a floating number that might be in the format of scientific notation from the keyboard.\nThen it will print it out with the scientific notation and without\n");
  double input;
  printf("Enter a number in scientific notation. (e.g. -4e-5 or -4.00e-5 or -4.00e-05 etc.)\n");
  scanf("%lf", &input);
  printf("With scientific notation '%e'\n", input);
  printf("Without scientific notation '%lf'\n", input);
  return 0;
}

Examples

This code will read a floating number that might be in the format of scientific notation from the keyboard.
Then it will print it out with the scientific notation and without
Enter a number in scientific notation. (e.g. -4e-5 or -4.00e-5 or -4.00e-05 etc.)
4.5e-10
With scientific notation '4.500000e-10'
Without scientific notation '0.000000'
This code will read a floating number that might be in the format of scientific notation from the keyboard.
Then it will print it out with the scientific notation and without
Enter a number in scientific notation. (e.g. -4e-5 or -4.00e-5 or -4.00e-05 etc.)
4.5e-3
With scientific notation '4.500000e-03'
Without scientific notation '0.004500'
Advertisements

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 (156 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 (267 downloads) ).

The example( asn1c_image - Full example - Demonstrating Bug (267 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 (267 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) (196 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) (196 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) (196 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) (583 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) (583 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) (583 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) (129 downloads)

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

list_helpers.c (compressed) (129 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) (129 downloads)

C/C++: Full example of using C code in a C++ project

The following set of code present a fully functioning example of using a simple C library as part of a CPP based project to print on screen.

Full example of using C code in a C++ project (compressed) (129 downloads)

The trick relies on encapsulating the C header definitions in the extern "C" declaration. extern "C" will make all function and variable names in C++ have C linkage. What this means at the compiler level is that the compiler will not modify the names so that the C code can link to them and use them using a C compatible header file containing just the declarations of your functions and variables.

Full example of using C code in a C++ project (compressed) (129 downloads)

main.c

#include "cpp_library.h"
#include "c_library.h"

extern "C" void c_hello_world();

int main() {

    cpp_hello_world();
    c_hello_world();
    return 0;
}

cpp_library.h

#ifndef CPP_BASE_CPP_LIBRARY_H
#define CPP_BASE_CPP_LIBRARY_H

void cpp_hello_world();

#endif //CPP_BASE_CPP_LIBRARY_H

cpp_library.cpp

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

void cpp_hello_world() {

    std::cout << "Hello, World!" << std::endl;
}

c_library.h

#ifndef CPP_BASE_C_LIBRARY_H
#define CPP_BASE_C_LIBRARY_H

#ifdef __cplusplus
extern "C" {
#endif

void c_hello_world();

#ifdef __cplusplus
}
#endif

#endif //CPP_BASE_C_LIBRARY_H

c_library.c

#include <stdio.h>
#include "c_library.h"

void c_hello_world() {

    printf("Hello, World!\n");
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.6)
project(CPP_Base)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.cpp cpp_library.cpp cpp_library.h c_library.c c_library.h)
add_executable(CPP_Base ${SOURCE_FILES})
Full example of using C code in a C++ project (compressed) (129 downloads)

C/C++: Full example of using C++ code in a C project

The following set of code present a fully functioning example of using a simple CPP library as part of a C based project to print on screen.

Full example of using C++ code in a C project (compressed) (130 downloads)

The trick relies on encapsulating the CPP header definitions in the extern "C" declaration. extern "C" will make all function and variable names in C++ have C linkage. What this means at the compiler level is that the compiler will not modify the names so that the C code can link to them and use them using a C compatible header file containing just the declarations of your functions and variables.

Full example of using C++ code in a C project (compressed) (130 downloads)

 

main.c

#include "cpp_library.h"
#include "c_library.h"

int main() {

    cpp_hello_world();
    c_hello_world();
    return 0;
}

cpp_library.h

#ifndef C_BASE_CPP_LIBRARY_H
#define C_BASE_CPP_LIBRARY_H

#ifdef __cplusplus
extern "C" {
#endif

void cpp_hello_world();

#ifdef __cplusplus
}
#endif

#endif //C_BASE_CPP_LIBRARY_H

cpp_library.cpp

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

void cpp_hello_world() {

    std::cout << "Hello, World!" << std::endl;
}

c_library.h

#ifndef C_BASE_C_LIBRARY_H
#define C_BASE_C_LIBRARY_H

void c_hello_world();

#endif //C_BASE_C_LIBRARY_H

c_library.c

#include <stdio.h>
#include "c_library.h"

void c_hello_world() {

    printf("Hello, World!\n");
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.6)
project(C_Base)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.c cpp_library.cpp cpp_library.h c_library.c c_library.h)
add_executable(C_Base ${SOURCE_FILES})
Full example of using C++ code in a C project (compressed) (130 downloads)

C/C++: Get the size of a file in bytes

The following function accepts the name of a file as a string and returns the size of the file in bytes. If for any reason it cannot get the file information, it will return the value -1.

get_file_size.c (compressed) (126 downloads)

In our header file, we used the following pre-processor directives around our declarations

#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

to allow c++ code to call our c function.

The usage example code makes three tests:

  1. Getting the size of the currently executing binary, as it will have a non-zero size
  2. Getting the size of a non-existing file, to check that it will properly return -1
  3. Getting the size of an empty file, to be sure it is empty we create it right before the test
get_file_size.c (compressed) (126 downloads)

Source file (file_helpers.c)

#include <sys/stat.h>
#include "file_helpers.h"

//It will return the size of the file in bytes OR -1 in case that it cannot get any status information for it
off_t get_file_size(const char *filename) {
  //Specialised struct that can hold status attributes of files.
  struct stat st;

  //Gets file attributes for filename and puts them in the stat buffer.
  // Upon successful completion, it returns 0, otherwise and errno will be set to indicate the error.
  if (stat(filename, &st) == 0) {
    //Size of file, in bytes.
    return st.st_size;
  }

  return -1;
}

Header file (file_helpers.h)

#ifndef GM_S_LITTLE_HELPERS_FILE_HELPERS_H
#define GM_S_LITTLE_HELPERS_FILE_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

off_t get_file_size(const char *filename);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_FILE_HELPERS_H

Usage example (main.cpp)

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

void print_file_size(const char *filename) {
  const off_t size_of_file = get_file_size(filename);
  if (size_of_file > 0) {
    printf("The size of '%s' is %zd bytes\n", filename, size_of_file);
  }
  else if (size_of_file == 0) {
    printf("The file '%s' is empty\n", filename);
  }
  else {
    printf("Could not get the status information for file '%s'\n", filename);
  }
}

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

  //Testing a non-zero sized file
  print_file_size(argv[0]);
  //Testing for a non-existing file
  print_file_size("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
  print_file_size(filename);

  return 0;
}
get_file_size.c (compressed) (126 downloads)

C/C++: Perform safe sprintf 1

The following function accepts the address of a char * buffer, the formatting string for printf along with all the parameters needed to fill the formatting string and updates the location of the buffer to point at the final formatted string.

safe_sprintf.c (130 downloads)

This code does not require the user to perform malloc before filling in the buffer. Using vsnprintf (variation of snprintf for variable arguments) it will automatically find the correct size that the buffer should have, allocate the space, switch the pointer of the buffer and prepare the final string using the formatting arguments.

In our header file, we used the following pre-processor directives around our declarations

#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

to allow c++ code to call our function.

safe_sprintf.c (130 downloads)

Source file (string_helpers.c)

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "string_helpers.h"

int safe_sprintf(char ** buffer, const char *format, ...) {

  va_list arguments;
  //The va_start(va_list arguments, last) macro initializes and must be called first.
  //The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
  va_start (arguments, format);

  //Upon successful return, vsnprintf 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 = vsnprintf(NULL, 0, format, arguments) + 1;

  //Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function.
  // After the call va_end(arguments) the variable arguments is undefined.
  // Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.
  va_end (arguments);

  if (*buffer) {
    free(*buffer);
  }
  if (!(*buffer = malloc(length * sizeof(char)))) {
    return EXIT_FAILURE;
  }

  va_start(arguments, format);
  vsnprintf(*buffer, (size_t) length, format, arguments);
  va_end (arguments);

  return EXIT_SUCCESS;
}

Header file (string_helpers.h)

#ifndef GM_S_LITTLE_HELPERS_STRING_HELPERS_H
#define GM_S_LITTLE_HELPERS_STRING_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

int safe_sprintf(char ** buffer, const char *format, ...);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_STRING_HELPERS_H

Usage example (main.cpp)

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

int main() {

  char * buffer;
  safe_sprintf(&buffer, "Hello, World!\nFrom Line %d in function %s of the file %s.", __LINE__, __func__, __FILE__);
  printf("%s", buffer);
  return 0;
}

safe_sprintf.c (130 downloads)