c 函数是否可以同时接受双参数和长双参数?

Is it possible for a c function to accept both double and long double arguments?

我在文件 mag.c 中有一个函数 mag,用于计算数组的大小。

#include <math.h>
#include "mag.h"

long double mag(long double arr[], int len){
    long double magnitude=0;
    for(int i=0;i<len;i++)
        magnitude+=pow(arr[i],2);
    magnitude=pow(magnitude,0.5);
    return magnitude;
}

我希望它接受双精度和长双精度数组。我在别处读过(例如 ),如果参数与函数声明不匹配,它将被隐式转换为正确的类型。我写了一个函数 test.c 来测试这个。

#include <math.h>
#include <stdio.h>
#include "mag.h"

int main(){
        double arr1[3]={0.0,1.1,2.2};
        printf("%Lf",mag(arr1,3));
        return 0;
}

但是,这产生了一个错误

test.c: In function ‘main’:
test.c:7:19: warning: passing argument 1 of ‘mag’ from incompatible pointer type [-Wincompatible-pointer-types]
  printf("%Lf",mag(arr1,3));
                   ^~~~
In file included from test.c:3:
mag.h:4:29: note: expected ‘long double *’ but argument is of type ‘double *’
 long double mag(long double arr[], int len);

将数组声明为 long double 允许函数正常工作。我还尝试更改头文件中的参数类型,但返回的是 -nan。有没有什么简单的方法可以让 mag 函数同时接受双参数和长双参数,或者制作两个单独的函数会更简单吗? (如果我需要为 double 和 long double 参数创建单独的函数,我需要为很多文件执行此操作。)

你说得对,如果可能的话,函数参数将隐式转换为预期类型。但是,这种隐式转换不会转换函数参数指向的对象或数组。它只会转换函数参数本身(即指针)。

因此,在 C 中,您将不得不创建两个单独的函数,或者做一些丑陋的事情,比如创建一个以 void * 作为参数的函数,该函数将被解释为 long double *double * 取决于附加参数的值:

#include <math.h>
#include <stdbool.h>

long double mag( void *arr, int len, bool is_long )
{
    long double magnitude=0;

    if ( is_long )
    {
        //interpret array as "long double"
        long double *arr_longdouble = arr;

        for( int i=0; i<len; i++ )
            magnitude += powl( arr_longdouble[i], 2 );
    }
    else
    {
        //interpret array as "double"
        double *arr_double = arr;

        for( int i=0; i<len; i++ )
            magnitude += powl( arr_double[i], 2 );
    }

    magnitude = powl( magnitude, 0.5 );
    return magnitude;
}

但是,C++(但不是 C)拥有您想要完成的目标的理想解决方案是毫无价值的。用那种语言,你可以制作一个 function template:

template <typename T>
T mag( T arr[], int len )
{
    T magnitude = 0;
    for( int i=0; i<len; i++ )
        magnitude += pow( arr[i], 2 );
    magnitude = pow( magnitude, 0.5 );
    return magnitude;
}

在此函数中,数据类型 T 可以是 doublelong double(或任何其他数据类型,只要代码可以编译)。编译器将根据需要自动为您创建一个 double and/or 一个 long double 版本的函数。

... it will be implicitly converted to the correct type. I wrote a function test.c to test this.

这适用于某些参数,例如 double 转换为 long double,但不适用于 double * 转换为 long double *

C 有 _Generic 就是为了这种编程。使用 mag(arr, len) _Generic((arr) ... 控制代码选择。

我建议还对 long double 个对象使用 long double 函数和 long double 常量。

long double mag_long_double(const long double arr[], int len) {
  long double magnitude = 0;
  for (int i = 0; i < len; i++)
    magnitude += powl(arr[i], 2);  // powl
  magnitude = sqrtl(magnitude);
  return magnitude;
}

double mag_double(const double arr[], int len) {
  double magnitude = 0;
  for (int i = 0; i < len; i++)
    magnitude += pow(arr[i], 2);
  magnitude = sqrt(magnitude);
  return magnitude;
}

#define mag(arr, len) _Generic((arr), \
  long double *: mag_long_double, \
  double *: mag_double \
  )((arr), (len))

int main(void) {
  double arr1[3] = {0.0, 1.1, 2.2};
  printf("%f\n",mag(arr1,3));
  long double arr2[3] = {0.0, 3.3L, 4.4L}; // Add 'L'
  printf("%Lf\n",mag(arr2,3));
  return 0;
}

输出

2.459675
5.500000