在包含浮点数的结构上使用 memset()
Using memset() on struct which contains a floating point number
在一个 C/C++ 混合项目中,我发现了一些可以减少到
的代码
#include <mem.h>
struct StructContainingDouble
{
double d;
/// other elements omitted
};
void clear(StructContainingDouble* p)
{
memset(p, 0, sizeof *p);
}
不停止 Cppcheck 以引发可移植性警告
Using memset() on struct which contains a floating point number.
消息是正确的,但是由于浮点数被声明为双精度,所以它似乎是误报,因为在双精度中,(正)零值是按照 IEEE 754 标准编码的: [*]
0 00000000000 0000000000000000000000000000000000000000000000000000
所以我倾向于简单地抑制警告并忘记它
void clear(ContainingDouble* p)
{
// cppcheck-suppress memsetClassFloat
memset(p, 0, sizeof *p);
}
但也许这里确实存在可移植性问题?
附录:
实际代码基于Win32平台。该结构用于管理对 shared memory 的访问,这就是构造函数无用的原因。不仅该结构的一个对象必须归零,而且它的一个数组嵌入到另一个结构中,如下所示:
#include <mem.h>
struct Slot
{
double d;
// more members...
};
struct SharedMem
{
Slot slots[2048];
// more members...
};
void clear(SharedMem* p)
{
memset(p, 0, sizeof *p);
}
已经提到 C 不保证任何特定的浮点实现。
嗯,C++ 也不行。不需要浮点值的特定实现。
[basic.fundamental]
There are three floating point types: float, double, and long double.
[...] The value representation of floating-point types is
implementation-defined.
因此,memset
-ing 浮点值在 C 或 C++ 中不可移植。
有问题吗?是的。不,不是真的。一个很遥远的也许。
正如 interjay 在评论中指出的那样,C 不强制要求浮点值的格式。所以理论上 'zeroes' 可能是无效值或不代表零。
所有具有 FPU 的现代平台都实现 IEEE 754。任何(可能是嵌入式)系统都不会在其库中实现 IEEE 754(除非它是退化的实现并且根本没有浮点...)。
因此,虽然不能保证您在这里遇到问题的可能性很小。
一些平台上存在关于它们如何精确地符合 IEEE 754 信件的细节问题,但之前曾问过但从未得到任何答案我会很高兴看到一个平台 memset()
一个带零的双精度数'将其设置为零值。
就是说,如果您开始加倍处理但使用零这不是问题,请不要忘记字节顺序。
记住 C 已经快 50 岁了,现在几乎通用的东西,比如一个字节是 8 位,还没有稳定下来,我认为这是为了提供最大的支持(不要忘记嵌入式) 它从未遵守这些标准。
在偏执模式下你可以选择:
memset(&obj,0,sizeof obj);
#ifndef __STDC_IEC_559__
obj.dbl_val=0.0;
#endif
其中 dbl_val
是 obj
的 double
成员。然而,未定义的唯一可能原因不是因为块归零不是零,而是标准的其他一些优点没有完全实现。
我认为在这种特殊情况下对可移植性的考虑太过分了。在我的生活中(我从事编程工作 30 多年),我还没有看到任何硬件或 C 实现中零表示除零之外的其他东西。当然,可以创建零不为零的任何数字格式(例如 BDC,数字由 ASCII 数字代码表示 - 但这里不是这种情况),但我们讨论的是真实存在的硬件和软件。
因此,IMO memset to zeroes 是安全且可移植的,即使标准说浮点数是实现定义的,因为我不知道任何现有的实现,其中零表示除零之外的其他东西,而且这样的实现是极其不切实际的.
实际代码用于在Windows (Win32) 下初始化共享内存。这意味着代码很可能会被移植(如果有的话)到某个具有适当 IEEE 754 支持的平台。
这就是为什么我建议 结合不可移植性:
使用 WinBase.h
中定义的 ZeroMemory
macro(通过 Windows.h
)来明确声明您没有尝试将一些花哨的位模式存储到浮点数中数据.
在该调用之前禁用 Cppcheck 的可移植性警告。
换句话说:
#include <windows.h>
// ...
void clear(SharedMem* p)
{
// cppcheck-suppress memsetClassFloat
ZeroMemory(p, sizeof *p);
}
在一个 C/C++ 混合项目中,我发现了一些可以减少到
的代码#include <mem.h>
struct StructContainingDouble
{
double d;
/// other elements omitted
};
void clear(StructContainingDouble* p)
{
memset(p, 0, sizeof *p);
}
不停止 Cppcheck 以引发可移植性警告
Using memset() on struct which contains a floating point number.
消息是正确的,但是由于浮点数被声明为双精度,所以它似乎是误报,因为在双精度中,(正)零值是按照 IEEE 754 标准编码的: [*]
0 00000000000 0000000000000000000000000000000000000000000000000000
所以我倾向于简单地抑制警告并忘记它
void clear(ContainingDouble* p)
{
// cppcheck-suppress memsetClassFloat
memset(p, 0, sizeof *p);
}
但也许这里确实存在可移植性问题?
附录:
实际代码基于Win32平台。该结构用于管理对 shared memory 的访问,这就是构造函数无用的原因。不仅该结构的一个对象必须归零,而且它的一个数组嵌入到另一个结构中,如下所示:
#include <mem.h>
struct Slot
{
double d;
// more members...
};
struct SharedMem
{
Slot slots[2048];
// more members...
};
void clear(SharedMem* p)
{
memset(p, 0, sizeof *p);
}
已经提到 C 不保证任何特定的浮点实现。
嗯,C++ 也不行。不需要浮点值的特定实现。
[basic.fundamental]
There are three floating point types: float, double, and long double. [...] The value representation of floating-point types is implementation-defined.
因此,memset
-ing 浮点值在 C 或 C++ 中不可移植。
有问题吗?是的。不,不是真的。一个很遥远的也许。
正如 interjay 在评论中指出的那样,C 不强制要求浮点值的格式。所以理论上 'zeroes' 可能是无效值或不代表零。
所有具有 FPU 的现代平台都实现 IEEE 754。任何(可能是嵌入式)系统都不会在其库中实现 IEEE 754(除非它是退化的实现并且根本没有浮点...)。
因此,虽然不能保证您在这里遇到问题的可能性很小。
一些平台上存在关于它们如何精确地符合 IEEE 754 信件的细节问题,但之前曾问过但从未得到任何答案我会很高兴看到一个平台 memset()
一个带零的双精度数'将其设置为零值。
就是说,如果您开始加倍处理但使用零这不是问题,请不要忘记字节顺序。
记住 C 已经快 50 岁了,现在几乎通用的东西,比如一个字节是 8 位,还没有稳定下来,我认为这是为了提供最大的支持(不要忘记嵌入式) 它从未遵守这些标准。
在偏执模式下你可以选择:
memset(&obj,0,sizeof obj);
#ifndef __STDC_IEC_559__
obj.dbl_val=0.0;
#endif
其中 dbl_val
是 obj
的 double
成员。然而,未定义的唯一可能原因不是因为块归零不是零,而是标准的其他一些优点没有完全实现。
我认为在这种特殊情况下对可移植性的考虑太过分了。在我的生活中(我从事编程工作 30 多年),我还没有看到任何硬件或 C 实现中零表示除零之外的其他东西。当然,可以创建零不为零的任何数字格式(例如 BDC,数字由 ASCII 数字代码表示 - 但这里不是这种情况),但我们讨论的是真实存在的硬件和软件。
因此,IMO memset to zeroes 是安全且可移植的,即使标准说浮点数是实现定义的,因为我不知道任何现有的实现,其中零表示除零之外的其他东西,而且这样的实现是极其不切实际的.
实际代码用于在Windows (Win32) 下初始化共享内存。这意味着代码很可能会被移植(如果有的话)到某个具有适当 IEEE 754 支持的平台。
这就是为什么我建议 结合不可移植性:
使用
WinBase.h
中定义的ZeroMemory
macro(通过Windows.h
)来明确声明您没有尝试将一些花哨的位模式存储到浮点数中数据.在该调用之前禁用 Cppcheck 的可移植性警告。
换句话说:
#include <windows.h>
// ...
void clear(SharedMem* p)
{
// cppcheck-suppress memsetClassFloat
ZeroMemory(p, sizeof *p);
}