R. F. Luis
R. F. Luis

Reputation: 99

c++ - Using zlib with const data

To compress/decompress data with zlib , first I need to set up a struct called z_stream. z_stream has two non-const pointers called next_in and next_out.

If I want to do a function like this:

void ungzip(std::vector<unsigned char>& dst,const std::vector<unsigned char>& src)
{
  z_stream strm;
  // more code
}

and other like,

void gzip  (std::vector<unsigned char>& dst,const std::vector<unsigned char>& src);

What I should do?

Copy src in a local std::vector<unsigned char>

std::vector<unsigned char> tmp(src);

and use it as source or setting pointer like this , strm.next_in = const_cast<char*>(&src[0])?

Does zlib keep input data?

Upvotes: 4

Views: 1158

Answers (1)

6502
6502

Reputation: 114481

Probably the cleanest way would be to just define ZLIB_CONST when compiling so that the input pointer is defined to be a const unsigned char * instead.

Note however that simply casting away const-ness is indeed going to work (it's legal if the character being pointed to is not actually constant). The code for this should be:

strm.next_in = (unsigned char *)&src[0];

or the uglier const_cast variant if you are into that kind of things.

Note that default in zlib is NOT to have ZLIB_CONST defined and if you want to use a precompiled zlib binary the casting solution is the best option. You should go for the ZLIB_CONST solution only if you're compiling yourself the library too with the same define(1).


(1) Giving the compiler an header with different semantic meaning is a bad idea - and a formal breaking of C++ standard rules - and it could - at least in theory - create protability problems.

With X86 architecture this is probably not the case and the library compiled with or without ZLIB_CONST would end up with the exact same bytes; however there are also different architectures.

For example I've been working with CPUs in which there were different pointer registers for different alignments. In that CPUs reading say an integer from an address that wasn't a multiple or 4 was an error generating an hardware trap (moreover something that at the time surprised me is that the error was triggered even by just assigning the pointer a non-aligned address, even if that misaligned address was never used for reading or writing).

With that compiler I didn't check (I was working only on high-level software) but I wouldn't be surprised if the system ABI specifed that a function void foo(char *) and void bar(int *) would have to receive the parameter in different registers.

More to the point, I never worked with but I can imagine may exist CPUs or VMs for which certain registers (let's name one as RW0) can be used for reading/writing operations and other registers (e.g. R0) can be used only for reading. With such an architecture the ABI may specify that the first parameter of type const char * must be passed in R0 and the first parameter of type char * must be passed in RW0 instead.

If this is the case compiling a library with a function void foo(char *p){...} and then compiling the calling code using as declaration void foo(const char *p); would actually end up passing the address in the wrong register!

Upvotes: 3

Related Questions