在C中编译期间更改函数体

在C中编译期间更改函数体,c,function,directive,conditional-compilation,C,Function,Directive,Conditional Compilation,假设我有一个如下的函数: void func1(...) { ... ... func2(...); ... ... } 在编译阶段,我在两个地方调用func1函数。但是,在其中一个地方,我不想执行func2 因此,在编译过程中我需要两个版本的func1:一个有func2,另一个没有func2 我知道以下方法。它们需要对电流源进行变形,我对此犹豫不决 将整个函数体放在define->中,然后使用此宏定义两个名称不同的函数。 将函数体放入另一个头文件中,并

假设我有一个如下的函数:

void func1(...) {
    ...
    ...
    func2(...);
    ...
    ...
}
在编译阶段,我在两个地方调用func1函数。但是,在其中一个地方,我不想执行func2

因此,在编译过程中我需要两个版本的func1:一个有func2,另一个没有func2

我知道以下方法。它们需要对电流源进行变形,我对此犹豫不决

将整个函数体放在define->中,然后使用此宏定义两个名称不同的函数。 将函数体放入另一个头文件中,并使用define宏控制执行路径。
除了上述方法之外,您还知道其他方法吗?

一种非常常见的方法是定义一个令牌,并将调用包装在ifdef块中检查令牌,无需重复func1,即:


显然,如何/在何处包含定义取决于您自己。您可以使用类似的方法。

一种非常常见的方法是定义令牌并将调用包装在ifdef块中检查令牌,无需重复func1,即:


显然,如何/在何处包含定义取决于您自己,您可以使用类似的方法。

而不是条件编译,特别是如果函数的其余部分是实质性的,您可以传递一个参数来指示是否应调用func2。该函数可以定义为:

void func1(..., bool call_func2) {
    ...
    ...
    if (call_func2)
        func2(...);
    ...
    ...
}
一个调用可能是func1…,true,另一个调用是func1…,false

如果您决定有时需要调用func2,有时需要调用func3,有时需要什么都不调用,则可以将函数参数更改为指向函数的指针:

void func1(..., void (*funcN)(...)) {
    ...
    ...
    if (funcN)
        funcN(...);
    ...
    ...
}
然后可以有func1…,func2,func1…,func3和func1…,NULL。打电话找找看。请注意,函数指针方案假定funcN函数具有统一的接口

否则,请查看是否需要重构函数

void func1A(...) {
    ...
    ...
    ...before call to func2...
}

void func1B(...) {
    ...after call to func2...
    ...
    ...
}

void func1(...) {
    func1A(...);
    func1B(...);
}

void func1plus2(...) {
    func1A(...);
    func2(...);
    func1B(...);
}

这些都比ifdef条件编译好。在第一个例子中,我可能会使用接口中的flag变量。

而不是条件编译,特别是如果函数的其余部分是实质性的,则可以传递一个参数来指示是否应调用func2。该函数可以定义为:

void func1(..., bool call_func2) {
    ...
    ...
    if (call_func2)
        func2(...);
    ...
    ...
}
一个调用可能是func1…,true,另一个调用是func1…,false

如果您决定有时需要调用func2,有时需要调用func3,有时需要什么都不调用,则可以将函数参数更改为指向函数的指针:

void func1(..., void (*funcN)(...)) {
    ...
    ...
    if (funcN)
        funcN(...);
    ...
    ...
}
然后可以有func1…,func2,func1…,func3和func1…,NULL。打电话找找看。请注意,函数指针方案假定funcN函数具有统一的接口

否则,请查看是否需要重构函数

void func1A(...) {
    ...
    ...
    ...before call to func2...
}

void func1B(...) {
    ...after call to func2...
    ...
    ...
}

void func1(...) {
    func1A(...);
    func1B(...);
}

void func1plus2(...) {
    func1A(...);
    func2(...);
    func1B(...);
}

这些都比ifdef条件编译好。在第一个例子中,我可能会使用接口中的flag变量。

3。将func2定义为宏。通过改变该宏的定义来控制是否调用该函数。如果处理不应相同,请不要使用相同的名称。你当然可以用宏来达到这个可怕的要求,但是维护将是一场噩梦!为func1提供一个额外的参数,告诉它是否执行func2。@PaulOgilvie:这是一个很好的方法,但它需要一个if语句,这会给我的平台带来沉重的负担。这就是为什么我通过使用编译标志来避免ifs,通过减少分支使运行时执行更加平滑。将func2定义为宏。通过改变该宏的定义来控制是否调用该函数。如果处理不应相同,请不要使用相同的名称。你当然可以用宏来达到这个可怕的要求,但是维护将是一场噩梦!为func1提供一个额外的参数,告诉它是否执行func2。@PaulOgilvie:这是一个很好的方法,但它需要一个if语句,这会给我的平台带来沉重的负担。这就是为什么我通过使用编译标志来避免ifs,从而通过减少分支使运行时执行更加平滑。这种方法的问题是,当编译func1时,它的主体被固定为具有或不具有func2。我无法更改其余编译的正文。考虑这一点:Fo{{…;函数1;…;}和bar {…;函数1;…;}。我希望func2在foo中执行,而不是在bar中执行。@Millad我不确定你的确切意思,使用这种方法,func2本身不会被编译出来,只是调用会被执行。好的是,虽然不能保证,但如果不存在对它的调用,一些编译器会编译出函数本身。如果您希望func2作为foo中的调用而不是bar中的调用存在,只需将其从bar中定义并保留在foo中即可。如果您希望在某个地方包含func2调用,但仅限于某些生成,您也可以在定义的指令中使用条件语句,例如if defined_BUILD_a | defined_BUILD_b当编译器尝试编译此代码时,它会到达
func1一次,根据是否定义了_INCLUDE_FUNC2_BUILD,编译func1。从现在起,func1的主体将被固定和指定。这是无法改变的。因此,对于调用func1的代码部分,我们无法控制何时调用func2。您是说希望根据运行时调用func1的位置来调用func2吗?是的。确切地对于func1的某些特定调用,我不想运行func2。剩下的,我确实想运行func2。为了强调,我需要用C而不是C++。这个方法的问题是,当函数1被编译时,它的主体被固定为函数2或不符。我无法更改其余编译的正文。考虑这一点:Fo{{…;函数1;…;}和bar {…;函数1;…;}。我希望func2在foo中执行,而不是在bar中执行。@Millad我不确定你的确切意思,使用这种方法,func2本身不会被编译出来,只是调用会被执行。好的是,虽然不能保证,但如果不存在对它的调用,一些编译器会编译出函数本身。如果您希望func2作为foo中的调用而不是bar中的调用存在,只需将其从bar中定义并保留在foo中即可。如果您想在某个地方包含func2调用,但只在某些生成中使用,您也可以在定义的指令中使用条件语句,例如if defined_BUILD_a | | defined_BUILD_b当编译器尝试编译此代码时,它会到达func1一次,并根据是否定义了_include_func2_BUILD,编译func1。从现在起,func1的主体将被固定和指定。这是无法改变的。因此,对于调用func1的代码部分,我们无法控制何时调用func2。您是说希望根据运行时调用func1的位置来调用func2吗?是的。确切地对于func1的某些特定调用,我不想运行func2。剩下的,我确实想运行func2。为了强调,我需要在C,而不是C++。谢谢这些方法。我的工作环境是,如果陈述是沉重的陈述,需要避免。第二种方法也是使用完全禁止的函数指针。然而,您最后一种方法更有意义,正如您所说的,ans更好。然而,它需要更广泛的代码重写,这是我正在避免的;如果测试条件足够可测量,我会有点惊讶。如果是的话,那么你很可能不得不选择ifdef黑客。除非该函数在单独的可执行文件中使用,否则您将需要两个名称-一个用于带调用,另一个不带调用。但是我担心你的代码的可维护性。谢谢你的方法。我的工作环境是,如果陈述是沉重的陈述,需要避免。第二种方法也是使用完全禁止的函数指针。然而,您最后一种方法更有意义,正如您所说的,ans更好。然而,它需要更广泛的代码重写,这是我正在避免的;如果测试条件足够可测量,我会有点惊讶。如果是的话,那么你很可能不得不选择ifdef黑客。除非该函数在单独的可执行文件中使用,否则您将需要两个名称-一个用于带调用,另一个不带调用。但是我担心你的代码的可维护性。