零双数组(使用memset(,0,))或包含双精度的结构是否合法?
这个问题意味着两件事:
(1)从C标准的角度来看,这个UB不是吗? (在一个固定的平台上,这个UB怎么样......它只取决于所有浮动表示......)
(2)从实际角度来看:在intel平台上可以吗? (无论标准是什么)。
答案 0 :(得分:30)
C99标准附件F说:
本附件规定了 IEC 60559浮点标准的C语言支持。该 IEC 60559浮点标准专门用于二进制浮点运算 先前指定的微处理器系统,第二版(IEC 60559:1989) IEC 559:1989 和 IEEE二进制浮点运算标准 (ANSI / IEEE 754-1985)。 IEEE标准的与基数无关的浮点 算术(ANSI / IEEE 854-1987)概括了要删除的二进制标准 对基数和字长的依赖性。 IEC 60559一般是指浮点数 标准,如IEC 60559操作,IEC 60559格式等。一种实现方式 定义
__STDC_IEC_559__
应符合本附件中的规范。哪里 指出了C语言与IEC 60559之间的绑定,IEC 60559规定 除非另有说明,否则行为均以引用方式采用。
并且,紧接着,
C浮点类型符合IEC 60559格式,如下所示:
float
类型符合IEC 60559单一格式。double
类型符合IEC 60559双重格式。
因此,如果IEC 60559基本上是IEEE 754-1985并且它指定8个零字节意味着0.0(如@David Heffernan所说),这意味着如果您发现__STDC_IEC_559__
已定义,则可以安全地进行0.0初始化与memset
。
答案 1 :(得分:14)
如果您正在谈论IEEE754,那么标准将+0.0定义为双精度为8个零字节。如果您知道自己受IEEE754浮点支持,那么这个定义很明确。
至于英特尔,我想不出在Intel x86 / x64上不使用IEEE754的编译器。
答案 2 :(得分:5)
David Heffernan对你问题的第(2)部分给出了一个很好的答案。第(1)部分:
C99标准不保证一般情况下浮点值的表示。 §6.2.6.1说:
除非本条款中另有说明,否则所有类型的陈述均未指明。
......而该子条款没有进一步提及浮点。
你说:
(在一个固定的平台上,这个UB怎么样......它只取决于浮动表示所有......)
确实 - “ undefined 行为”,“未指定的行为”和“实现定义的行为”之间存在差异:
所以,由于浮点表示是未指定的行为,它可以从平台到平台以无记录的方式变化(其中“平台”在这里表示“硬件和编译器的组合”而不仅仅是“硬件”)。
(我不确定如果double
被定义为+0.0
,如果定义了__STDC_IEC_559__
,则所有位为零的保证是有用的,如Matteo Italia的回答中所述实际上是在实践中。例如,GCC never defines this,即使在许多硬件平台上使用IEEE 754 / IEC 60559。)
答案 3 :(得分:4)
即使你不太可能遇到有问题的机器,如果你真的在谈论问题标题中指出的数组,你也可以相对容易地避免这种情况,如果这些数组在编译时已知长度(即不 VLA),然后只是初始化它们可能更方便:
double A[133] = { 0 };
应始终有效。如果你不得不再次将这样的数组归零,并且你的编译器符合现代C(C99),你可以用复合文字
memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));
在任何现代编译器上,它应该与memset
一样高效,但具有不依赖于double
的特定编码的优势。
答案 4 :(得分:2)
正如Matteo Italia所说,根据标准,这是合法的,但我不会使用它。像
这样的东西double *p = V, *last = V + N; // N - count
while(p != last) *(p++) = 0;
至少快两倍。
答案 5 :(得分:0)
好吧,我认为归零是“合法的”(毕竟,它是将常规缓冲区归零),但我不知道该标准是否允许您假设所得到的逻辑值。我的猜测是C标准将其保留为未定义。
答案 6 :(得分:0)
使用memset是“合法的”。问题是它是否产生一个数组[x] == 0.0为真的位模式。虽然基本的C标准并不要求它是真的,但我有兴趣听到它不是的例子!
在IBM-AIX,HP-UX(PARISC),HP-UX(IA-64),Linux(IA-64,我认为)上,memset似乎相当于0.0。
{
double dFloat1 = 0.0;
double dFloat2 = 111111.1111111;
memset(&dFloat2, 0, sizeof(dFloat2));
if(dFloat1 == dFloat2)
{
fprintf(stdout, "memset appears to be equivalent to = 0.0\n");
}
else
{
fprintf(stdout, "memset is NOT equivalent to = 0.0\n");
}
}