c++ - 将 zlib 与 const 数据一起使用
c++ - Using zlib with const data
要使用 zlib 获取 compress/decompress 数据,首先我需要设置一个名为 z_stream
的结构。
z_stream
有两个非常量指针 next_in
和 next_out
.
如果我想做这样的功能:
void ungzip(std::vector<unsigned char>& dst,const std::vector<unsigned char>& src)
{
z_stream strm;
// more code
}
和其他类似的,
void gzip (std::vector<unsigned char>& dst,const std::vector<unsigned char>& src);
我该怎么办?
复制src到本地std::vector<unsigned char>
std::vector<unsigned char> tmp(src);
并像这样将其用作源或设置指针,strm.next_in = const_cast<char*>(&src[0])
?
zlib 是否保留输入数据?
可能最简洁的方法是在编译时只定义 ZLIB_CONST
,这样输入指针就被定义为 const unsigned char *
。
但是请注意,简单地丢弃 const-ness 确实可行(如果指向的字符实际上不是常量,这是合法的)。
代码应该是:
strm.next_in = (unsigned char *)&src[0];
或者更丑陋的 const_cast
变体,如果你喜欢那种东西。
请注意,zlib
中的默认设置未定义 ZLIB_CONST
,如果您想使用预编译的 zlib
二进制文件,则转换解决方案是最佳选择。仅当您也使用相同的 define(1).
自己编译库时,才应该选择 ZLIB_CONST
解决方案
(1) 为编译器提供具有不同语义含义的 header 是一个坏主意 - 并且正式违反 C++ 标准规则 - 它可能 - 至少在理论上 - 会产生可移植性问题。
对于 X86 架构,情况可能并非如此,使用或不使用 ZLIB_CONST
编译的库将以完全相同的字节结束;但是也有不同的架构。
例如,我一直在使用 CPU,其中有不同的指针寄存器用于不同的对齐方式。在那个 CPU 中,从一个不是倍数或 4 的地址读取的整数是生成硬件陷阱的错误(此外,当时令我惊讶的是,即使只是分配指针 a [=54 也会触发错误=] 地址,即使该未对齐的地址从未用于读取或写入)。
我没有检查那个编译器(我只在 high-level 软件上工作)但是如果系统 ABI 指定函数 void foo(char *)
和 void bar(int *)
必须在不同的寄存器中接收参数。
更重要的是,我从未使用过但我可以想象可能存在某些寄存器(我们将其命名为 RW0
)可用于 reading/writing 操作和其他操作的 CPU 或 VM寄存器(例如 R0
)只能用于读取。
使用这样的体系结构,ABI 可以指定类型 const char *
的第一个参数必须在 R0
中传递,而类型 char *
的第一个参数必须在 RW0
中传递。
如果是这种情况,用函数 void foo(char *p){...}
编译库,然后使用 as 声明编译调用代码 void foo(const char *p);
实际上最终会在错误的寄存器中传递地址!
要使用 zlib 获取 compress/decompress 数据,首先我需要设置一个名为 z_stream
的结构。
z_stream
有两个非常量指针 next_in
和 next_out
.
如果我想做这样的功能:
void ungzip(std::vector<unsigned char>& dst,const std::vector<unsigned char>& src)
{
z_stream strm;
// more code
}
和其他类似的,
void gzip (std::vector<unsigned char>& dst,const std::vector<unsigned char>& src);
我该怎么办?
复制src到本地std::vector<unsigned char>
std::vector<unsigned char> tmp(src);
并像这样将其用作源或设置指针,strm.next_in = const_cast<char*>(&src[0])
?
zlib 是否保留输入数据?
可能最简洁的方法是在编译时只定义 ZLIB_CONST
,这样输入指针就被定义为 const unsigned char *
。
但是请注意,简单地丢弃 const-ness 确实可行(如果指向的字符实际上不是常量,这是合法的)。 代码应该是:
strm.next_in = (unsigned char *)&src[0];
或者更丑陋的 const_cast
变体,如果你喜欢那种东西。
请注意,zlib
中的默认设置未定义 ZLIB_CONST
,如果您想使用预编译的 zlib
二进制文件,则转换解决方案是最佳选择。仅当您也使用相同的 define(1).
ZLIB_CONST
解决方案
(1) 为编译器提供具有不同语义含义的 header 是一个坏主意 - 并且正式违反 C++ 标准规则 - 它可能 - 至少在理论上 - 会产生可移植性问题。
对于 X86 架构,情况可能并非如此,使用或不使用 ZLIB_CONST
编译的库将以完全相同的字节结束;但是也有不同的架构。
例如,我一直在使用 CPU,其中有不同的指针寄存器用于不同的对齐方式。在那个 CPU 中,从一个不是倍数或 4 的地址读取的整数是生成硬件陷阱的错误(此外,当时令我惊讶的是,即使只是分配指针 a [=54 也会触发错误=] 地址,即使该未对齐的地址从未用于读取或写入)。
我没有检查那个编译器(我只在 high-level 软件上工作)但是如果系统 ABI 指定函数 void foo(char *)
和 void bar(int *)
必须在不同的寄存器中接收参数。
更重要的是,我从未使用过但我可以想象可能存在某些寄存器(我们将其命名为 RW0
)可用于 reading/writing 操作和其他操作的 CPU 或 VM寄存器(例如 R0
)只能用于读取。
使用这样的体系结构,ABI 可以指定类型 const char *
的第一个参数必须在 R0
中传递,而类型 char *
的第一个参数必须在 RW0
中传递。
如果是这种情况,用函数 void foo(char *p){...}
编译库,然后使用 as 声明编译调用代码 void foo(const char *p);
实际上最终会在错误的寄存器中传递地址!