我听说c ++程序员应该避免使用memset,
class ArrInit {
//! int a[1024] = { 0 };
int a[1024];
public:
ArrInit() { memset(a, 0, 1024 * sizeof(int)); }
};
Run Code Online (Sandbox Code Playgroud)
所以考虑到上面的代码,如果你不使用memset,怎么能把[1..1024]填充为0?在C++中memset有什么问题?
谢谢.
如果C编译器填充结构以便将字段与其原始对齐对齐,然后初始化该结构,则填充是否初始化为零?
例如以下结构:
typedef struct foo_t_ {
int a;
char b;
int c;
char d;
} foo_t;
Run Code Online (Sandbox Code Playgroud)
在许多系统上,这个(设计不佳)的结构将具有sizeof(foo_t)16个,总共6个字节的填充,每个字符后3个字节.
如果我们初始化结构,如:
foo_t foo = { .a = 1, .b = '2' };
Run Code Online (Sandbox Code Playgroud)
然后字段foo.a将设置为1并将foo.b设置为字符"2".未指定的字段(`foo.c'和'foo.d')将自动设置为0.问题是,6个字节的填充会发生什么?那还会自动设置为0吗?还是未定义的行为?
用例是我将计算数据结构的哈希值:
foo_t foo = { .a = 1, .b = '2' };
foo_t bar = { .a = 1, .b = '2' };
uint32_t hash_foo = calc_hash(&foo, sizeof(foo));
uint32_t hash_bar = calc_hash(&bar, sizeof(bar));
Run Code Online (Sandbox Code Playgroud)
我想确定hash_foo并且hash_bar是一样的.我可以通过首先使用memset()清除结构然后初始化它来保证这一点,但是使用C初始化代替它似乎更清晰.
在实践中,我的系统上的GCC也确实清除了填充,但我不知道这是否有保证.
#include<cstring>
struct A {
char a;
int b;
};
int main() {
A* a = new A();
a->a = 1;
unsigned char m[sizeof(A)];
std::memcpy(m, a, sizeof(A));
return m[1];
}
Run Code Online (Sandbox Code Playgroud)
除了由于分配失败而可能出现的异常以及假设在和之间0至少有一个填充字节之外,该程序是否保证以 C++ 中的状态退出?abA
new A()进行值初始化,因为A的默认构造函数很简单,但既不是用户提供的也不是删除的,因此将对象的所有成员和填充字节归零A。
对于 C,N1570(C11 草案)中的 6.2.6.1p6 对我来说似乎暗示填充字节在分配给成员后处于未指定的状态,尽管我可能会误解这一点(请参阅评论)。但无论如何,我在 C++ 标准(草案)中没有看到任何允许这样做的规则。
受此启发,如果在第二个(不兼容)示例中分配给成员,则零初始化结构的填充可能会泄漏信息。但请注意,该示例的描述无论如何都是错误的,因为它实际上执行聚合初始化,而不是值初始化,因此没有零初始化。
这是我之前在问题中使用的代码的两个类似版本,但由于与我用来检查对象表示的方法不相关的问题,它们可能具有 UB(请参阅注释):
#include<new>
struct A {
char a;
int b;
};
int main() {
unsigned char* m = new unsigned char[sizeof(A)];
A* a = new(m) A(); …Run Code Online (Sandbox Code Playgroud)