有没有办法在不包含 <complex.h> 的情况下声明一个复数?

Is there a way to declare a complex number without including <complex.h>?

我想使用<complex.h> 库来加速一些计算,其中可能包含多达 20 个复杂元素和运算 (+ - * /)。但是,我的同事声明了一个结构:

struct complex {
    double a;
    double b;
};

因此,由于与上述结构冲突,无法使用来自库的complex宏。

问题是,由于对当前项目的巨大影响,我无法更改结构的名称。我尝试改用 _Complex 宏,并删除了 #include <complex.h> header,它起作用了,但 _Imaginary_I_Complex_II 不起作用。

#include <stdio.h>      /* Standard Library of Input and Output */
// #include <complex.h>    /* I want to remove this */    

int main() {
    struct complex
    {
        double a;
        double b;
    };
    double _Complex z1 = 1.0;// + 3.0 * _Complex_I;
    double _Complex z2 = 1.0;// - 4.0 * _Complex_I;    

    // none of these work
    double _Complex z = CMPLX(0.0, -0.0);
    double _Complex z3 = 1.0 + 1.0 * _Imaginary_I;
    double _Complex z4 = 1.0 + 1.0 * _Complex_I;
    double _Complex z5 = 1.0 + 1.0 * I;    

    printf("Starting values: Z1 = %.2f + %.2fi\n", creal(z1), cimag(z1));    

}

我希望有一种方法可以区分来自库的复杂宏和定义的复杂结构。遗憾的是我无法更改结构,所以事情变得出乎意料地复杂了。

我的 __STDC_VERSION__201112L,而 __VERSION__ 是“4.2.1 兼容的 Apple LLVM 10.0.1 (clang-1001.0.46.4)”。

C 标准预料到了这个问题,并有一个专门针对它的条款,7.3.1p7:

Notwithstanding the provisions of 7.1.3, a program may undefine and perhaps then redefine the macros complex, imaginary, and I.

这意味着,你可以这样做:

#include <stdio.h>
#include <complex.h>
#undef complex     /* after including complex.h, before declaring struct complex */

//#include <header_that_defines_struct_complex.h>
struct complex
{
    double a;
    double b;
};

现在您的代码可以毫无问题地使用 struct complexdouble _Complex,并且可以访问 <complex.h>.

中声明的复杂数学函数
int main(void)
{
    // this should all be fine now
    double _Complex z = CMPLX(0.0, -0.0);
    double _Complex z1 = 1.0 + 3.0 * _Complex_I;
    double _Complex z2 = 1.0 - 4.0 * _Complex_I;    
    double _Complex z3 = 1.0 + 1.0 * _Imaginary_I;
    double _Complex z4 = 1.0 + 1.0 * _Complex_I;
    double _Complex z5 = 1.0 + 1.0 * I;    
    printf("Starting values: Z1 = %.2f + %.2fi\n", creal(z1), cimag(z1));    

    return 0;
}

但是请注意,无法使 struct complex 自动转换为 "compatible with"、double _Complex,即使它们在内存中的布局可能相同。您将不得不手动来回复制。

或者您可以重新定义在 the_other_colleagues_header

中定义的结构体
#define complex my_complex
#include <the_other_colleagues_header>
#undef complex

#include <complex.h>

现在,在您的 .c 文件中,您可以同时使用 complexmy_complex,而其他人仍然可以正常使用 struct complex。或者为 complex.h 编写一个包装器并从您的应用程序中调用它

但更好的解决办法是让另一位同事改名。使用标准名称通常是个坏主意

你的实际问题是

my colleague has declared a struct:

    struct complex {
        double a;
        double b;
    };

解决这个问题。

解决这个问题的所有其他方法都会创建事实上撤消标准C功能的未记录依赖 -宏的定义 complex。您的组织要做的最好的事情可能就是 "On page 4 of our coding standards [you do have coding standards?], it states that you have to #undef complex after you #include <complex.h>, then you have to #include <stomps/on/complex.h> after that"。您的组织实际做这么多的可能性有多大?然后确保计划中的每个人都知道这一点?

很可能,他们不会为此付出努力,他们甚至不会接近。

您将获得一些未记录的部落知识。

同样,您的组织是否有书面的编码标准,并实际执行它们?如果您不能对此做出肯定回答,那么您确实确实需要现在就真正解决问题的根本原因,而不是将其埋葬,等待将来造成更严重的问题。

struct complex 不仅创建了对撤消标准 C 功能的依赖,而且还创建了对 #include 指令和 #undef 语句的排序依赖。没有真正的方法可以知道如果不严格遵守这些依赖关系会发生什么 - 不能排除未来几年出现奇怪的结果和无法解释的故障。

是的,用 #undef complex 取消定义宏是合法的,而且并不难。但是,如果有人不这样做,或者以错误的顺序这样做,会发生什么?

如果您做得对,编写和维护软件已经够难的了。最好不要故意做一些有问题的事情,让程序的生命周期变得更难。