今天早上我们发现一大堆代码导致库调用崩溃。
struct fred
{
int a;
int b;
int c;
};
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(fred) * MAX_SIZE+1 );
看起来sizeof(fred)可能是完整的数组大小,而不是结构大小,因为它覆盖了很多的内存。
它在几个不同的系统上没有警告地编译的事实看起来很奇怪。
这种类型和变量名称冲突的情况是否存在正确的语义? 或者这是某种未定义的行为?或只是一个缺陷?
答案 0 :(得分:14)
排名第一,不要这样做,因为它令人困惑 - 但你已经发现了这一点。
变量隐藏了struct的名称,但您仍然可以使用struct fred
来引用该类型。
e.g。
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(struct fred) * (MAX_SIZE+1) );
或者,为什么不使用完整对象的大小。这样,面对数组大小或类型的更改,您的memset
调用是健壮的。你可以这样做:
memset( fred, 0, sizeof fred );
在使用带有sizeof
的类型ID时,必须具有括号,但在使用对象时不需要它。
答案 1 :(得分:2)
这不应该是sizeof(fred)*(MAX_SIZE + 1),因为你的数组是MAX_SIZE + 1长吗?
答案 2 :(得分:2)
最新声明优先:
[C++03: 9.1/2]:
类定义将类名引入定义它的范围,并在封闭范围内隐藏该名称的任何类,对象,函数或其他声明(3.3)。 如果在声明了同名对象,函数或枚举器的作用域中声明了类名,那么当两个声明都在作用域中时,只能使用详细说明的类来引用该类。 type-specifier (3.4.4)。
详细说明类型说明符是指将struct
或class
粘贴在该类型的前面;但是,严格地说,这有效地消除了它的歧义,并且由于上面引用的规则,查询从一开始就不是真的含糊不清。
所以:
void foo()
{
struct bar {};
bar bar[5];
memset(bar, 0, sizeof(bar));
// ^^^^^^^^^^^
// 5
memset(bar, 0, sizeof(struct bar));
// ^^^^^^^^^^^^^^^^^^
// 1
}
// (NB. Exact sizes may differ; 1 and 5 given as relative examples only)
事实上,这一切都是明确定义的,这是你没有得到警告的一个原因。不过,我希望希望智能编译器会将您的代码视为可能的程序员错误 - 合理化为什么某些给定的实现在某些非强制性情况下会发出或不发出某些警告,但是,很愚蠢。
答案 3 :(得分:1)
当你定义变量时,它会隐藏类型的名称,所以是的,当你执行sizeof(fred)
时,你得到的是数组的大小,而不是结构的大小。只需打印sizeof(fred)
即可轻松验证这一点。
然而,简短的回答只是:“不要这样做。”
答案 4 :(得分:0)
除运行时大小的案例外,使用memset
(以及memcpy
,malloc
等)的典型惯用方法是
memset(dst_ptr, 0, sizeof *dst_ptr);
或等同地
memset(&dst_object, 0, sizeof dst_object);
在这种情况下应该如何使用
memset(&fred, 0, sizeof fred);
并且不会出现名称冲突的问题。 memset(fred, 0, sizeof fred)
变体也可以使用。