简体   繁体   English

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

[英]Is a C99 complex type binary compatible with a structure with two members?

Can I use typedef struct {double r; double i;} DC;我可以使用typedef struct {double r; double i;} DC; typedef struct {double r; double i;} DC; as a binary compatible data type for C99 double complex type?作为 C99 double complex类型的二进制兼容数据类型?

My experimental C code works in my case (gcc / x86-64 / Linux).我的实验性 C 代码适用于我的情况(gcc / x86-64 / Linux)。 But is this universally valid ?但这是否普遍有效

/* 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;
}

The program's output is here:程序的输出在这里:

i = 0, c[i].r = 1.000000 c[i].i = 10.000000
i = 1, c[i].r = -0.100000 c[i].i = -0.200000
i = 2, c[i].r = 3.000000 c[i].i = 30.000000

The pattern I have found most reliable for testing whether gcc will recognize aliasing between two types is exemplified by:我发现用于测试 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;
}

The generated code for gcc 7.1 is gcc 7.1 生成的代码是

.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

The return value of the function is in xmm0, which is loaded from dd->r and tested against zero.函数的返回值在 xmm0 中,它从 dd->r 加载并针对零进行测试。 If it's non-zero, code stores a new value to *cd, but does not reload the value in xmm0.如果它不为零,则代码将新值存储到 *cd,但不会重新加载 xmm0 中的值。

I'm not sure for what purpose the authors of the Standard specified how complex numbers are stored given that they did not in turn make them alias-compatible with anything else, but gcc attaches more importance to the fact that the Standard doesn't mandate that it recognize aliasing than to the fact that being able to alias layout-compatible types is useful.我不确定标准的作者为了什么目的指定了复数的存储方式,因为他们并没有使它们与其他任何东西别名兼容,但是 gcc 更重视标准没有强制要求的事实它识别别名而不是能够为布局兼容的类型别名是有用的这一事实。

Yes, my copy of the C11 standard says (I assume C99 says the same):是的,我的 C11 标准副本说(我假设 C99 说相同):

Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type;每个复数类型与包含对应实数类型的两个元素的数组类型具有相同的表示和对齐要求; the first element is equal to the real part, and the second element to the imaginary part, of the complex number.第一个元素等于复数的实部,第二个元素等于复数的虚部。

Assuming no padding is added between or after members (as it most likely will not be), your struct is binary compatible with _Complex double .假设在成员之间或之后没有添加填充(因为它很可能不会添加),则您的struct_Complex double二进制兼容。

Obviously the keyword is "assuming" which implies not universally valid.显然,关键字是“假设”,这意味着并非普遍有效。 Hence the above text from the standard.因此,上述文本来自标准。

If you want universally valid, you'd want to use:如果你想要普遍有效,你会想要使用:

double val[2]; // double _Complex

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM