C++ 我可以安全地用公共头中的未签名字符替换bool成员吗?
我提供了一个公共头,用户根据它编译,以利用其中包含的类。我需要修复实现这些公共类之一的共享库中的一个问题,并要求现有用户在安装修补程序时无需重新编译其库。修复要求bool成员能够保存比false、true更多的信息。 这个班看起来像C++ 我可以安全地用公共头中的未签名字符替换bool成员吗?,c++,C++,我提供了一个公共头,用户根据它编译,以利用其中包含的类。我需要修复实现这些公共类之一的共享库中的一个问题,并要求现有用户在安装修补程序时无需重新编译其库。修复要求bool成员能够保存比false、true更多的信息。 这个班看起来像 class PublicAPI{ ... public: bool getSync(); void setSync(bool sync); ... private bool sync_; ... }; 我想更改bool-sync\ux;到无符号字符同步
class PublicAPI{
...
public:
bool getSync();
void setSync(bool sync);
...
private
bool sync_;
...
};
我想更改bool-sync\ux;到无符号字符同步代码>:
class PublicAPI{
...
public:
bool getSync();
void setSync(bool sync);
...
private
unsigned char sync_;
...
};
注意,能手和二传手不会,我认为他们也不会改变。他们会没事的,因为用户不需要知道sync_uuu包含的附加值,我将处理在内部保留我的值。显然,这是一个丑陋的黑客行为,但我认为技术上这是可以的,因为类的大小不会改变
我担心的是,我在Linux、AIX、HPUX、Solaris和Windows上提供的平台之一上的编译器会使用我不知道的bool类型玩一些游戏,并破坏某些东西
有没有想过这有多安全或危险?我敢肯定,从技术上讲,您会调用未定义的行为。然而,我认为在实际应用中,没有编译器会进行这种更改。我非常确定,从技术上讲,您会调用未定义的行为。然而,我认为在实际应用中,没有编译器会加入这种更改。如果sizeof(bool)=sizeof(char),因此类的大小将不同。如果您有一个使用旧头编译的模块,并且有一个新的二进制文件,那么这可能会给您带来麻烦。
为了避免编译问题,只需确保您可以进行强制转换,并且应该是正常的。if sizeof(bool)=sizeof(char),因此类的大小将不同。如果您有一个使用旧头编译的模块,并且有一个新的二进制文件,那么这可能会给您带来麻烦。
为了避免编译问题,只需确保您进行了强制转换并且应该是正常的。我认为没有一种方法可以保证安全地执行您想要的操作。对于bool
和unsigned char
,某些编译器可能具有不同的大小
在大多数编译器上,这种情况似乎不太可能发生,您可能会侥幸逃脱。当然,最好是“建议”重新编译,但允许它在不重新编译的情况下工作
这是一个完美的例子,在这个例子中,pimpl’s实现可以消除任何问题,因为内部类型将完全隐藏在库中,而不是公开。我认为没有一种方法可以保证安全。对于bool
和unsigned char
,某些编译器可能具有不同的大小
在大多数编译器上,这种情况似乎不太可能发生,您可能会侥幸逃脱。当然,最好是“建议”重新编译,但允许它在不重新编译的情况下工作
这是一个完美的例子,在这个例子中,pimpl'ing您的实现可以消除任何问题,因为内部类型将完全隐藏在您的库中,而不是公开。从技术上讲,它是未定义的行为,在实践中,它几乎
当然不行——函数名会被弄乱
(修饰)不同,链接器将无法找到
功能
在大多数此类情况下,解决方案是使用旧的
功能转发到新功能,例如
public:
void setSync(bool sync);
void setSync(int sync);
,通过setSync(bool sync)
实现为:
void PublicAPI::setSync(bool sync)
{
setSync(sync ? 1 : 0);
}
不要使setSync的新实现内联。(如果
旧的一个实际上是内联的,你完蛋了。)从技术上讲,它是未定义的行为,实际上,它几乎是
当然不行——函数名会被弄乱
(修饰)不同,链接器将无法找到
功能
在大多数此类情况下,解决方案是使用旧的
功能转发到新功能,例如
public:
void setSync(bool sync);
void setSync(int sync);
,通过setSync(bool sync)
实现为:
void PublicAPI::setSync(bool sync)
{
setSync(sync ? 1 : 0);
}
不要使setSync的新实现内联。(如果
以前的一个实际上是内联的,你被搞砸了。)我不知道GCC,但很久以前我用MSVC 6做了一些类似的攻击(大多数攻击都是用指针替换DWORD)。工作很好。
当然,正如许多其他人已经写过的,sizeof(无论你使用什么)必须等于sizeof(bool)。
不过这不应该是个问题,因为您可以随时使用
class PublicAPI{
...
public:
bool getSync();
void setSync(bool sync);
...
private
unsigned char sync_[sizeof(bool)];
...
};
然后在内部使用sync\u0]
。我不知道GCC,但很久以前我用MSVC 6做过一些类似的攻击(大多数攻击都是用指针替换DWORD)。工作很好。
当然,正如许多其他人已经写过的,sizeof(无论你使用什么)必须等于sizeof(bool)。
不过这不应该是个问题,因为您可以随时使用
class PublicAPI{
...
public:
bool getSync();
void setSync(bool sync);
...
private
unsigned char sync_[sizeof(bool)];
...
};
然后在内部使用sync\u0]
。最安全的方法是使用bool
和无符号字符的联合。当bool
大于char
时,该并集将像bool一样对齐,但仍包含char
bool
和char
都是POD类型,所以没什么大不了的。所有访问都是通过两个非内联成员进行的(您确定它们不是内联的?即未在类中定义?),这意味着您总是通过char
成员访问联合体。最安全的方法是使用bool
和unsigned char
的联合体。当bool
大于char
时,该并集将像bool一样对齐,但仍包含char
bool
和char
都是POD类型,所以没什么大不了的。所有访问都是通过两个非内联成员进行的(您确定它们不是内联的?即,未在类中定义?),这意味着您总是通过char
成员访问union。如果您可以这样编程,您根本不需要更改头文件:
#include <iostream>
using namespace std ;
static bool b ;
int main()
{
unsigned char u0 = 99 ;
*reinterpret_cast<unsigned char*>(&b) = u0 ;
unsigned char u1 = *reinterpret_cast<unsigned char*>(&b) ;
cout << int(u1) << endl ;
}