簡體   English   中英

是否可以“typedef”(各種)一個函數原型?

[英]Is it possible to “typedef”(of sorts) a function prototype?

我有多個彼此相似的函數 - 它們接受相同的參數,並返回相同的類型:

double mathFunction_1(const double *values, const size_t array_length);

我已經使用了typedef'd指向那些函數的指針,因為我將它們存儲為一個數組,以便在相同的數據上輕松使用它們,映射它們等:

typedef double (* MathFunction_ptr )(const double *, const size_t);

double proxy(MathFunction_ptr mathfun_ptr, const double *values, const size_t array_length);

我想要實現的是與聲明和定義函數類似的易用性,就像我已經使用指針一樣。


因此,我正在考慮使用類似的typedef來讓我更容易編寫實際的函數。 我嘗試這樣做:

// declaration
typedef double MathFunction (const double *values, const size_t array_length);
MathFunction mathFunction_2;

以下方法部分起作用。 它允許我在聲明中“保存一些鍵擊”,但是必須完全輸入定義。

double mathFunction_2(const double *values, const size_t array_length)
{
    // ...
}

我通過搜索更多這個問題找到的是: 函數原型typedef可以用在函數定義中嗎?

然而,它沒有提供很多替代方案,只是重申我根據標准禁止在我的其他實驗中嘗試做的事情。 它提供的唯一選擇是使用

#define FUNCTION(name) double name(const double* values, size_t array_length)

這聽起來很笨(因為我對使用預處理器持謹慎態度和懷疑態度)。

我正在嘗試做什么的替代方案是什么?


我試過的另外兩種方法不起作用(而且,正如我剛才所讀,根據C標准6.9.1禁止和絕對錯誤):

1.這種方法不起作用,因為這意味着我告訴它定義一個變量mathFunction_2(我相信變量被視為一個指針,雖然我還不太了解它),就像一個函數:

MathFunction mathFunction_2
{
    // ...
}

2.這種方法不起作用,因為它意味着我告訴它創建一個返回函數的函數(在C語言中不可接受):

MathFunction mathFunction_2()
{
    // ...
}

您可以使用typedef進行簽名(另請參閱此內容 ):

typedef double MathFunction_ty (const double *, const size_t);

然后聲明相同簽名的幾個函數:

MathFunction_ty func1, func2;

或者使用它聲明一些函數指針

MathFunction_ty* funptr;

等......所有這些都在C11中 ,讀取n1570

但是必須完全輸入定義。

當然,因為你需要給一個名稱 ,每個形參(並且這樣的名字都沒有的功能的類型的一部分)在函數的定義 因此

double func1(const double*p, const size_t s) {
  return (double)s * p[0];
}

double func1(cont double*arr, const size_t ix) {
   return arr[ix];
}

具有相同的類型(上面用MathFunction_ty表示的類型),即使它們的形式參數(或形式參數)的命名方式不同。

您可能濫用預處理器並使用丑陋的宏來縮短此類函數的定義

// ugly code:
#define DEFINE_MATH_FUNCTION(Fname,Arg1,Arg2) \
   double Fname (const double Arg1, const size_t Arg2)
DEFINE_MATH_FUNCTION(func1,p,s) { return (double)s * p[0]; }

我發現這樣的代碼令人困惑且難以理解。 我不建議這樣編碼,即使它確實可行。 但有時我會編寫類似的東西(出於其他原因)。

(順便說一句,想象一下,如果C 要求每個第一個正式參數被命名為$1 ,每個第二個正式參數被命名為$2 ,等等......;恕我直言,這將使得編程語言的可讀性低得多;因此正式參數的名稱對人類讀者很重要即使系統名稱會使編譯器的生命更簡單)

另請閱讀關於λ演算匿名函數 (C沒有它們但C ++有lambda表達式 ), 閉包 (它們不是 C函數,因為它們具有封閉值,因此將代碼與數據混合; C ++具有std::function -s ), 回調 (“模仿”閉包的必要約定 )...閱讀SICP ,它將改善你對C或C ++的思考。 再看看那個答案。

不幸的是,CI不相信沒有任何方法可以在不使用預處理器宏的情況下完成您的要求,至少我個人同意您的評估他們很笨重並且要避免(盡管這是一個意見和開放的問題)辯論)。

在C ++中,您可以利用lambda中auto參數

您在此處顯示的示例函數簽名確實並不復雜,我不擔心感知到的重復。 如果簽名要復雜得多,我會認為這是一個“代碼氣味”,你的設計可以改進,我會集中精力在那里而不是語法方法來縮短聲明。 這不是這里的情況。

是的你可以。 實際上,這就是typedef聲明的目的,即使用類型標識符來聲明一種變量。 唯一的事情是當你在頭文件中使用這樣的聲明時:

 typedef int (*callback_ptr)(int, double, char *);

然后你聲明如下:

 callback_ptr function_to_callback;

你不清楚你是在聲明一個函數指針以及參數的數量和類型,但盡管如此,一切都是正確的。

最后,我想特別注意一些事情。 當你處理這樣的事情時,通常會更便宜,更快速地去編譯器並嘗試一些例子。 如果編譯器在沒有任何投訴的情況下完成您想要的操作,那么最可能的事情就是您是正確的。

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

typedef double (*ptr_to_mathematical_function)(double);

extern double find_zero(ptr_to_mathematical_function f, double aprox_a, double aprox_b, double epsilon);

int main()
{
#define P(exp) printf(#exp " ==> %lg\n", exp)

    P(find_zero(cos, 1.4, 1.6, 0.000001));
    P(find_zero(sin, 3.0, 3.2, 0.000001));
    P(find_zero(log, 0.9, 1.5, 0.000001));
}

double find_zero(
    ptr_to_mathematical_function f, 
    double a, double b, double eps)
{
    double f_a = f(a), f_b = f(b);
    double x = a, f_x = f_a;

    do {
        x = (a*f_b - b*f_a) / (f_b - f_a);
        f_x = f(x);

        if (fabs(x - a) < fabs(x - b)) {
           b = x; f_b = f_x;
        } else {
            a = x; f_a = f_x;
        }
    } while(fabs(a-b) >= eps);
    return x;
}

問題的第二個主要部分,如果遇到這樣的問題,唯一可以解決的問題就是使用宏(請參閱我如何使用類似但不相同的參數列表重復上述printf(3)函數調用,以及如何在下面解決問題):

#define MY_EXPECTED_PROTOTYPE(name) double name(double x)

然后,在定義中,只需使用:

MY_EXPECTED_PROTOTYPE(my_sin) {
    return sin(x);
}

MY_EXPECTED_PROTOTYPE(my_cos) {
    return cos(x);
}

MY_EXPECTED_PROTOTYPE(my_tan) {
    return tan(x);
}
...

這將擴展到:

double my_sin(double x) {
...
double my_cos(double x) {
...
double my_tan(double x) {
...

你甚至可以在頭文件中使用它,例如:

MY_EXPECTED_PROTOTYPE(my_sin);
MY_EXPECTED_PROTOTYPE(my_cos);
MY_EXPECTED_PROTOTYPE(my_tan);

正如其他答案所指出的那樣,還有其他語言(C ++)支持這個以及更多,但我認為這超出了范圍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM