-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix C++ style casts #19
Conversation
#include <gzip/decompress.hpp> | ||
#include <gzip/utils.hpp> | ||
#include <gzip/version.hpp> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^ this is unrelated to fixing casts. Rather it is best practice to always include files the same way with <>
consistently.
@@ -1,8 +1,10 @@ | |||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<iostream>
was uneeded, so I removed. But to keep the code compiling I needed to add <string>
(turns out was being included by ).
@@ -0,0 +1,5 @@ | |||
#pragma once | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea here is to define the ZLIB_CONST
in one place. Hence this new header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea to use this for other things as well? Like WERROR, for example?
@@ -47,7 +50,7 @@ std::string decompress(const char* data, std::size_t size) | |||
{ | |||
output.resize(length + 2 * size); | |||
inflate_s.avail_out = static_cast<unsigned int>(2 * size); | |||
inflate_s.next_out = (Bytef*)(output.data() + length); | |||
inflate_s.next_out = reinterpret_cast<Bytef*>(&output[0] + length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
output.data()
returns a const value. But in this case output.data()
is the pointer we write to - so we need the non-const/mutable pointer here.
@@ -1,4 +1,7 @@ | |||
#include <cstdlib> | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This include is needed for this header to compile on its own, since uint8_t
is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@springmeyer just left a couple questions - thanks for your in-line comments!
include/gzip/compress.hpp
Outdated
// zlib | ||
#include <zlib.h> | ||
// std | ||
#include <limits> | ||
#include <string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like make format
tests are failing due to alphabetical order here .. just need to move below stdexcept
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thank you for noticing - fixed in 912a7f8
@@ -57,7 +59,7 @@ std::string compress(const char* data, | |||
// There is no way we see that "increase" would not fit in an unsigned int, | |||
// hence we use static cast here to avoid -Wshorten-64-to-32 error | |||
deflate_s.avail_out = static_cast<unsigned int>(increase); | |||
deflate_s.next_out = (Bytef*)(output.data() + length); | |||
deflate_s.next_out = reinterpret_cast<Bytef*>((&output[0] + length)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@springmeyer mind explaining why reinterpret_cast
instead of static or another?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proximately because a static_cast
would not compile:
/Users/dane/projects/gzip-hpp/include/gzip/compress.hpp:62:30: error:
static_cast from 'value_type *' (aka 'char *') to 'Bytef *'
(aka 'unsigned char *') is not allowed
deflate_s.next_out = static_cast<Bytef*>((&output[0] + length));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Which means the previous C
style cast was doing the equivalent of a reinterpret_cast
under the hood. A reinterpret
is needed because we are changing a char *
to an unsigned char *
. We are doing this because a char *
is what is stored inside std::string
per http://en.cppreference.com/w/cpp/string/basic_string. While zlib's next_out
uses a Bytef
pointer and a Bytef
is type def'd to a Byte
which is type def'd to an unsigned char
at https://github.com/madler/zlib/blob/cacf7f1d4e3d44d871b605da3b647f07d718623f/zconf.h#L391.
So our options are either:
- Make the types the same
- Cast
In this case I'm casting since that is what the previous code did. Also because the only way I can think of making the types the same is to use a std::vector<unsigned char>
instead of a std::string
and I think std::string
is ideal since that is what has been in use.
If you want to know the difference between char *
and unsigned char*
and why zlib uses unsigned
I'm not sure - I'd need to tag in @joto for an opinion.
reinterpret_casting between |
@joto - really helpful - that addresses my gaps in knowledge and concerns - thank you 🙏 |
Fixes the compiler warnings/errors that arose from #18
Context
We should be using C++ style casts instead of C style casts. While C style casts allow for multiple types of casting to happen in one, C++ style casts require you to be explicit.
Previous to this PR we were casing a
const char *
into aunsigned char
. So both a reinterpret cast (to go fromchar
tounsigned char
is needed) and aconst_cast
to drop theconst
.After studying the code I realized we don't want to do the
const_cast
- we'd be removing theconst
from data that truly is const and should not be modified, which is bad practice.Then I noticed that zlib has a
ZLIB_CONST
define that can be turned on to allow for const data to be passed in. This is ideal so that we don't need to cast it away.I noticed it can be enabled here: https://github.com/madler/zlib/blob/cacf7f1d4e3d44d871b605da3b647f07d718623f/zconf.h#L234
Which makes the
z_const
define non-blank. So, this PR moves to C++ style casts and avoids the need for a const cast.It looks like this will mean that the minimum zlib version we can support will now be zlib 1.2.5.2 per nodejs/node#9110. I think this is fine.
Refs mapbox/cpp#37