Daily Archives: 7 December 2016


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.

[download id=”2434″]

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.

[download id=”2434″]

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})

[download id=”2434″]


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.

[download id=”2428″]

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.

[download id=”2428″]

 

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})

[download id=”2428″]


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.

[download id=”2417″]

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

[download id=”2417″]

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;
}

[download id=”2417″]


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.

[download id=”2418″]

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.

[download id=”2418″]

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;
}

[download id=”2418″]