HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

C++ demo code for interaction with C

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withinteractionforcodedemo

Problem

I want to show how to interact with C from C++ and chose a simple and small library to demonstrate. zlib's gzopen, gzwrite and gzclose looked like a reasonably closed set of funtions.

Does anyone see anything fundamentally wrong with my presentaion? The main code I present here is in class GzWrite.

Intro section:

#include 
#include 
#include  // ifstream
#include  // runtime_error
#include  // cerr
// C-Headers:
#include  // gzXyz; sudo aptitude install libz-dev
#include  // strerror
#include  // errno
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
using std::ifstream; using std::ofstream; using std::string; using std::vector;
namespace {

constexpr size_t BLOCK_SZ = 256*1024;
constexpr int LEVEL = Z_DEFAULT_COMPRESSION;


Core class

struct GzWrite { // RAII-Wrapper
    gzFile gz_ ; // C-Struct aus zlib.h
    explicit GzWrite(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
    {
        if(gz_==NULL) throw std::runtime_error(strerror(errno));
    }
    ~GzWrite() {
        gzclose(gz_);
    }
    int write(const char* data, size_t len) {
        return gzwrite(gz_, data, len);
    }
    GzWrite(const GzWrite&) = delete; // no copy
    GzWrite& operator=(const GzWrite&) = delete; // no assign
};


Helper functions

```
vector read(const string& infn) {
ifstream inf{ infn, ifstream::binary };
if(!inf) throw std::runtime_error("open error");
inf.seekg(0, inf.end); // go to end of file
const auto laenge = inf.tellg(); // current pos is file size
if(laenge > 102410241024) throw std::runtime_error(" data(laenge); // make room
inf.read(data.data(), laenge); // read all at once
return std::move(data); // make doubly sure data is not copied
}

void pack(const string& infn, const string& outfn) {
vector indata = read(infn); // read input
GzWrite gz{outfn}; // init output
auto res = gz.write(indata.data(), indata.size());
if(res==0)

Solution

This example is mostly about making and using a RAII wrapper, not about calling C from C++ (which is trivial).

If you want to show how to call C-like interfaces, then use zlib directly, without wrapping it.

If you want to show the native C++ way to wrap a C interface, then the wrapper should be an iostream subclass, like gzstream.

pack should read blocks of finite size rather than reading the whole file at once. It's a compression utility, so it's likely to be used on files that won't fit in memory!

Some confusing names:

  • GzWrite instances aren't writes; they're streams. How about GzStream or (if it uses the iostreams interface) gzostream?



  • Don't call a function read; it's easy to confuse with Posix read. This is traditionally called slurp or read_file.



  • infn will probably be interpreted as "in-function", not "in-filename". How about infile?



  • laenge (Länge?): length



BLOCK_SZ and LEVEL are unused.

Context

StackExchange Code Review Q#51292, answer score: 6

Revisions (0)

No revisions yet.