首选方法,使用两个名称在C中调用同一个函数

时间:2022-08-03 03:47:21

I know there are at least three popular methods to call the same function with multiple names. I haven't actually heard of someone using the fourth method for this purpose.

我知道至少有三种常用的方法可以用多个名称调用同一个函数。我还没有听说过有人为此使用第四种方法。

1). Could use #defines:

1)。可以使用#定义:

int my_function (int);


#define my_func my_function

OR

#define my_func(int (a)) my_function(int (a))

2). Embedded function calls are another possibility:

2).嵌入式函数调用是另一种可能:

int my_func(int a) {
    return my_function(a);
}

3). Use a weak alias in the linker:

3).在链接器中使用弱别名:

int my_func(int a) __attribute__((weak, alias("my_function")));

4). Function pointers:

4)函数指针:

int (* const my_func)(int) = my_function;

The reason I need multiple names is for a mathematical library that has multiple implementations of the same method.

我需要多个名称的原因是一个数学库具有相同方法的多个实现。

For example, I need an efficient method to calculate the square root of a scalar floating point number. So I could just use math.h's sqrt(). This is not very efficient. So I write one or two other methods, such as one using Newton's Method. The problem is each technique is better on certain processors (in my case microcontrollers). So I want the compilation process to choose the best method.

例如,我需要一个有效的方法来计算标量浮点数的平方根。我可以用数学。h sqrt()。这不是很有效。我写了一两种方法,比如用牛顿法。问题是每种技术在某些处理器上都更好(在我的例子中是微控制器)。所以我希望编译过程选择最好的方法。

I think this means it would be best to use either the macros or the weak alias since those techniques could easily be grouped in a few #ifdef statements in the header files. This simplifies maintenance (relatively). It is also possible to do using the function pointers, but it would have to be in the source file with extern declarations of the general functions in the header file.

我认为这意味着最好使用宏或弱别名,因为这些技术很容易在头文件中的几个#ifdef语句中进行分组。这简化了维护(相对)。也可以使用函数指针,但它必须在源文件中,头文件中有通用函数的extern声明。

Which do you think is the better method?

你认为哪种方法更好?


Edit:

编辑:

From the proposed solutions, there appears to be two important questions that I did not address.

从提出的解决办法来看,似乎有两个重要的问题我没有提及。

Q. Are the users working primarily in C/C++?

问:用户主要使用C/ c++吗?

A. All known development will be in C/C++ or assembly. I am designing this library for my own personal use, mostly for work on bare metal projects. There will be either no or minimal operating system features. There is a remote possibility of using this in full blown operating systems, which would require consideration of language bindings. Since this is for personal growth, it would be advantageous to learn library development on popular embedded operating systems.

所有已知的开发都将是C/ c++或汇编语言。我设计这个图书馆是为了我自己的个人用途,主要是为了做裸金属项目。操作系统的特性要么是不存在的,要么是最小的。在完全成熟的操作系统中使用它的可能性很小,这需要考虑语言绑定。因为这是为了个人成长,所以在流行的嵌入式操作系统上学习库开发是很有好处的。

Q. Are the users going to need/want an exposed library?

用户需要或想要一个公开的库吗?

A. So far, yes. Since it is just me, I want to make direct modifications for each processor I use after testing. This is where the test suite would be useful. So an exposed library would help somewhat. Additionally, each "optimal implementation" for particular function may have a failing conditions. At this point, it has to be decided who fixes the problem: the user or the library designer. A user would need an exposed library to work around failing conditions. I am both the "user" and "library designer". It would almost be better to allow for both. Then non-realtime applications could let the library solve all of stability problems as they come up, but real-time applications would be empowered to consider algorithm speed/space vs. algorithm stability.

答:到目前为止,是的。因为只有我一个人,所以我想对我测试后使用的每个处理器进行直接修改。这就是测试套件有用的地方。因此,一个公开的库会有所帮助。此外,每个特定函数的“最佳实现”都可能有一个失败的条件。在这一点上,必须决定由谁来解决问题:用户还是库设计人员。用户需要一个公开的库来处理失败的条件。我既是“用户”又是“图书馆设计师”。考虑到这两种情况会更好。然后非实时应用程序可以让库在出现时解决所有稳定性问题,但实时应用程序将被授权考虑算法速度/空间和算法稳定性。

5 个解决方案

#1


7  

Depending on the intended audience for your library, I suggest you chose between 2 alternatives:

根据您图书馆的目标读者,我建议您选择以下两种选择:

  1. If the consumer of your library is guaranteed to be Cish, use #define sqrt newton_sqrt for optimal readability

    如果您的库的使用者保证是Cish,那么使用#define sqrt newton_sqrt以获得最佳的可读性。

  2. If some consumers of your library are not of the C variety (think bindings to Dephi, .NET, whatever) try to avoid consumer-visible #defines. This is a major PITA for bindings, as macros are not visible on the binary - embedded function calls are the most binding-friendly.

    如果您的库的某些使用者不是C类(请考虑到Dephi、. net等的绑定),请尽量避免使用可见的#定义。这是绑定的主要问题,因为在二进制内嵌的函数调用中看不到宏,这是最适合绑定的。

#2


6  

Another alternative would be to move the functionality into a separately compiled library optimised for each different architecture and then just link to this library during compilation. This would allow the project code to remain unchanged.

另一种选择是将功能移动到为每个不同的体系结构优化的单独编译库中,然后在编译期间链接到这个库。这将允许项目代码保持不变。

#3


4  

What you can do is this. In header file (.h):

你能做的就是这个。在头文件(. h):

 int function(void);

In the source file (.c):

在源文件(.c)中:

static int function_implementation_a(void);
static int function_implementation_b(void);
static int function_implementation_c(void);

#if ARCH == ARCH_A
int function(void)
{
    return function_implementation_a(); 
}
#elif ARCH == ARCH_B
int function(void)
{
    return function_implementation_b();
}
#else
int function(void)
{
    return function_implementation_c();
}
#endif // ARCH

Static functions called once are often inlined by the implementation. This is the case for example with gcc by default : -finline-functions-called-once is enabled even in -O0. The static functions that are not called are also usually not included in the final binary.

被称为once的静态函数通常由实现内联。这就是默认情况下gcc的情况:-finline-functions- caled -once在-O0中启用。未调用的静态函数通常也不包含在最终的二进制文件中。

Note that I don't put the #if and #else in a single function body because I find the code more readable when #if directives are outside the functions body.

注意,我没有将#if和#else放在一个函数体中,因为我发现当#if指令位于函数体之外时,代码更容易读懂。

Note this way works better with embedded code where libraries are usually distributed in their source form.

注意,这种方法在嵌入式代码中工作得更好,在这些代码中,库通常以源代码的形式分布。

#4


3  

I usually like to solve this with a single declaration in a header file with a different source file for each architecture/processor-type. Then I just have the build system (usually GNU make) choose the right source file.

我通常喜欢用头文件中的单个声明来解决这个问题,头文件中每个架构/处理器类型都有不同的源文件。然后我让构建系统(通常是GNU make)选择正确的源文件。

I usually split the source tree into separate directories for common code and for target-specific code. For instance, my current project has a toplevel directory Project1 and underneath it are include, common, arm, and host directories. For arm and host, the Makefile looks for source in the proper directory based on the target.

我通常将源代码树分割成单独的目录,用于通用代码和特定于目标的代码。例如,我当前的项目有一个toplevel目录Project1,在它下面有common、arm和主机目录。对于arm和主机,Makefile基于目标在适当的目录中查找源文件。

I think this makes it easier to navigate the code since I don't have to look up weak symbols or preprocessor definitions to see what functions are actually getting called. It also avoids the ugliness of function wrappers and the potential performance hit of function pointers.

我认为这样可以更容易地浏览代码,因为我不需要查找弱符号或预处理器定义来查看实际调用的函数。它还避免了函数包装器的丑陋性和函数指针潜在的性能冲击。

#5


0  

You might you create a test suite for all algorithms and run it on the target to determine which are the best performing, then have the test suite automatically generate the necessary linker aliases (method 3).

您可以为所有算法创建一个测试套件,并在目标上运行它以确定哪个是最佳执行,然后让测试套件自动生成必要的链接器别名(方法3)。

Beyond that a simple #define (method 1) probably the simplest, and will not and any potential overhead. It does however expose to the library user that there might be multiple implementations, which may be undesirable.

除此之外,一个简单的#define(方法1)可能是最简单的,不会有任何潜在的开销。但是,它向库用户公开可能有多个实现,这可能是不可取的。

Personally, since only one implementation of each function is likley to be optimal on any specific target, I'd use the test suite to determine the required versions for each target and build a separate library for each target with only those one version of each function the correct function name directly.

就我个人而言,因为只有likley每个函数的一种实现在任何特定的最优目标,我使用测试套件来确定所需的版本为每个目标和建立一个单独的库为每个目标只有一个版本的每个函数直接正确的函数名。

#1


7  

Depending on the intended audience for your library, I suggest you chose between 2 alternatives:

根据您图书馆的目标读者,我建议您选择以下两种选择:

  1. If the consumer of your library is guaranteed to be Cish, use #define sqrt newton_sqrt for optimal readability

    如果您的库的使用者保证是Cish,那么使用#define sqrt newton_sqrt以获得最佳的可读性。

  2. If some consumers of your library are not of the C variety (think bindings to Dephi, .NET, whatever) try to avoid consumer-visible #defines. This is a major PITA for bindings, as macros are not visible on the binary - embedded function calls are the most binding-friendly.

    如果您的库的某些使用者不是C类(请考虑到Dephi、. net等的绑定),请尽量避免使用可见的#定义。这是绑定的主要问题,因为在二进制内嵌的函数调用中看不到宏,这是最适合绑定的。

#2


6  

Another alternative would be to move the functionality into a separately compiled library optimised for each different architecture and then just link to this library during compilation. This would allow the project code to remain unchanged.

另一种选择是将功能移动到为每个不同的体系结构优化的单独编译库中,然后在编译期间链接到这个库。这将允许项目代码保持不变。

#3


4  

What you can do is this. In header file (.h):

你能做的就是这个。在头文件(. h):

 int function(void);

In the source file (.c):

在源文件(.c)中:

static int function_implementation_a(void);
static int function_implementation_b(void);
static int function_implementation_c(void);

#if ARCH == ARCH_A
int function(void)
{
    return function_implementation_a(); 
}
#elif ARCH == ARCH_B
int function(void)
{
    return function_implementation_b();
}
#else
int function(void)
{
    return function_implementation_c();
}
#endif // ARCH

Static functions called once are often inlined by the implementation. This is the case for example with gcc by default : -finline-functions-called-once is enabled even in -O0. The static functions that are not called are also usually not included in the final binary.

被称为once的静态函数通常由实现内联。这就是默认情况下gcc的情况:-finline-functions- caled -once在-O0中启用。未调用的静态函数通常也不包含在最终的二进制文件中。

Note that I don't put the #if and #else in a single function body because I find the code more readable when #if directives are outside the functions body.

注意,我没有将#if和#else放在一个函数体中,因为我发现当#if指令位于函数体之外时,代码更容易读懂。

Note this way works better with embedded code where libraries are usually distributed in their source form.

注意,这种方法在嵌入式代码中工作得更好,在这些代码中,库通常以源代码的形式分布。

#4


3  

I usually like to solve this with a single declaration in a header file with a different source file for each architecture/processor-type. Then I just have the build system (usually GNU make) choose the right source file.

我通常喜欢用头文件中的单个声明来解决这个问题,头文件中每个架构/处理器类型都有不同的源文件。然后我让构建系统(通常是GNU make)选择正确的源文件。

I usually split the source tree into separate directories for common code and for target-specific code. For instance, my current project has a toplevel directory Project1 and underneath it are include, common, arm, and host directories. For arm and host, the Makefile looks for source in the proper directory based on the target.

我通常将源代码树分割成单独的目录,用于通用代码和特定于目标的代码。例如,我当前的项目有一个toplevel目录Project1,在它下面有common、arm和主机目录。对于arm和主机,Makefile基于目标在适当的目录中查找源文件。

I think this makes it easier to navigate the code since I don't have to look up weak symbols or preprocessor definitions to see what functions are actually getting called. It also avoids the ugliness of function wrappers and the potential performance hit of function pointers.

我认为这样可以更容易地浏览代码,因为我不需要查找弱符号或预处理器定义来查看实际调用的函数。它还避免了函数包装器的丑陋性和函数指针潜在的性能冲击。

#5


0  

You might you create a test suite for all algorithms and run it on the target to determine which are the best performing, then have the test suite automatically generate the necessary linker aliases (method 3).

您可以为所有算法创建一个测试套件,并在目标上运行它以确定哪个是最佳执行,然后让测试套件自动生成必要的链接器别名(方法3)。

Beyond that a simple #define (method 1) probably the simplest, and will not and any potential overhead. It does however expose to the library user that there might be multiple implementations, which may be undesirable.

除此之外,一个简单的#define(方法1)可能是最简单的,不会有任何潜在的开销。但是,它向库用户公开可能有多个实现,这可能是不可取的。

Personally, since only one implementation of each function is likley to be optimal on any specific target, I'd use the test suite to determine the required versions for each target and build a separate library for each target with only those one version of each function the correct function name directly.

就我个人而言,因为只有likley每个函数的一种实现在任何特定的最优目标,我使用测试套件来确定所需的版本为每个目标和建立一个单独的库为每个目标只有一个版本的每个函数直接正确的函数名。