在双精度数组上使用memset(,0,)是否合法?

时间:2011-01-07 20:15:56

标签: c standards

零双数组(使用memset(,0,))或包含双精度的结构是否合法?

这个问题意味着两件事:

(1)从C标准的角度来看,这个UB不是吗? (在一个固定的平台上,这个UB怎么样......它只取决于所有浮动表示......)

(2)从实际角度来看:在intel平台上可以吗? (无论标准是什么)。

7 个答案:

答案 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 行为”,“未指定的行为”和“实现定义的行为”之间存在差异:

  • undefined 行为”表示任何事情都可能发生(包括运行时崩溃);
  • 未指定的行为”意味着编译器可以自由地以任何方式实现某些合理的东西,但不要求记录实现选择;
  • 实现定义的行为”意味着编译器可以自由地以任何方式实现合理的东西,并且应该记录该选择(例如,请参阅here最新版本的GCC);
  • 记录的实施选择

所以,由于浮点表示是未指定的行为,它可以从平台到平台以无记录的方式变化(其中“平台”在这里表示“硬件和编译器的组合”而不仅仅是“硬件”)。

(我不确定如果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");
    }
}