C99复杂类型二进制文件是否与具有两个成员的结构兼容?

C99复杂类型二进制文件是否与具有两个成员的结构兼容?,c,c99,complex-numbers,C,C99,Complex Numbers,我可以使用typedef结构{double r;double I;}DC 作为C99double complex类型的二进制兼容数据类型 我的实验性C代码在我的示例(gcc/x86-64/Linux)中工作。但是这是否普遍有效 /* gcc -o test test.c (WORKS) */ /* gcc -O3 -march=native -o test test.c (WORKS with volatiles) */ #include <stdio.h> #include &l

我可以使用
typedef结构{double r;double I;}DC
作为C99
double complex
类型的二进制兼容数据类型

我的实验性C代码在我的示例(gcc/x86-64/Linux)中工作。但是这是否普遍有效

/* gcc -o test test.c (WORKS) */
/* gcc -O3 -march=native -o test test.c (WORKS with volatiles) */

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>

typedef struct {
    double r;
    double i;
} DC;

int main()
{
    /* var */
    const int N = 3;

    volatile DC *c = malloc(N*sizeof(DC));

    volatile double complex *z;
    z = (double complex *) c;

    int i;

    /* init */
    for(i=0; i<N; i++)
    {
       c[i].r = (double) i+1;
       c[i].i = (double) (i+1) * 10;
    }
    z[1] = -0.1 -0.2*I; // THE POINT IS HERE

    /* results */
    for(i=0; i<N; i++)
    printf("i = %d, c[i].r = %f c[i].i = %f\n", i, c[i].r, c[i].i);

    /* end */
    free((void*) c);

    return 0;
}

是的,我的C11标准副本上说(我假设C99也这么说):

每种复合类型都具有相同的表示和对齐方式 要求作为一个数组类型,正好包含 对应的实型第一个元素等于实部, 第二个元素是复数的虚部

假设没有在成员之间或之后添加填充(很可能不会),则您的
结构
\u Complex double
是二进制兼容的

显然,关键字是“假定”,这意味着不是普遍有效的。因此,上述文本来自标准

如果您想要普遍有效,您需要使用:

double val[2]; // double _Complex

我发现,测试gcc是否能够识别两种类型之间的混叠最可靠的模式是:

#include <complex.h>
typedef struct  { double r,i; } d2;

double test(double complex *cd, d2 *dd)
{
  if (dd->r)
    *cd = 1.0;
  return dd->r;
}
函数的返回值是xmm0,它是从dd->r加载的 并以零为基准进行测试。如果它不是零,则代码将新值存储到 *cd,但不重新加载xmm0中的值


我不确定该标准的作者指定复数的存储方式是为了什么目的,因为它们没有使复数与其他任何东西兼容,但gcc更重视的是,该标准并不要求它识别别名,而不是能够为与布局兼容的类型别名是有用的。

“假设没有填充”!=“普遍有效”你的回答暗示的问题是,“不能普遍假设任何填充物吗?”@AndrewHenle我认为我的回答暗示了这一点。提供了一些解释。谢谢,这很有用!但是,我可能需要知道结构中是否没有填充(在所有平台上…),以便我可以使用结构而不是数组。(原因是我想在vala中使用C99复杂类型,似乎我只能将其作为结构进行接口)@DeiDei它可能是-我正在仔细考虑。这种假设感觉是正确的,因为如果由于假设平台上的平台限制而将结构填充到特定的对齐方式,那么出于相同的原因,数组元素需要进行类似的对齐。在现代C语言中,两种类型的布局兼容并不意味着可以使用指向一种类型的指针来访问另一种类型。除非有明确授权豁免上述结构的别名规则,否则我不相信gcc或clang能够有效地处理上述代码,除非是在
-fno strict aliasing
模式下。假设没有其他方法可以做到这一点,您可能需要添加几个静态断言来测试这些类型的
sizeof
/
alignof
/
offset
及其成员是否匹配。但这并不是完美的保证。@user694733:更重要的问题是,是否可以依靠gcc和clang来识别c[i]和z[i]之间的潜在别名。不幸的是,没有办法对此进行测试。
#include <complex.h>
typedef struct  { double r,i; } d2;

double test(double complex *cd, d2 *dd)
{
  if (dd->r)
    *cd = 1.0;
  return dd->r;
}
.LC1:
        .long   0
        .long   1072693248
        .long   0
        .long   0
test:
        movsd   xmm0, QWORD PTR [rsi]
        ucomisd xmm0, QWORD PTR .LC0[rip]
        jp      .L4
        je      .L1
.L4:
        movsd   xmm1, QWORD PTR .LC1[rip]
        movsd   QWORD PTR [rdi], xmm1
        movsd   xmm1, QWORD PTR .LC1[rip+8]
        movsd   QWORD PTR [rdi+8], xmm1
.L1:
        rep ret
.LC0:
        .long   0
        .long   0