簡體   English   中英

C - 高階函數

[英]C - Higher Order Function

Signal 將回調函數作為其參數之一。 為了具有可變行為,我想在函數內創建一個函數。 到目前為止,這是我的嘗試:

typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
    void sigintHandler(int sig) {
        printf("Process %d", pid);
    }
    return sigintHandler
}

int main(void) {
    ...
    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        ...
    }
    ...
}

但是,每次我發送 SIGTSTP (Ctrl-z) 時,都會出現段錯誤。


作為旁注:關於如何調試段錯誤的任何提示將不勝感激!

您的代碼可以編譯,因為它在語法上是正確的,並且您使用的是編譯器擴展; 但是,您的代碼存在一些基本問題,可能會導致您的segfault

首先,您的信號處理程序代碼:

typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
    void sigintHandler(int sig) {
        printf("Process %d", pid);
    }
    return sigintHandler;
}

不是標准的 C 語言,甚至需要在某些版本的gcc上指定-ftrampolines標志才能實際編譯。

您的信號處理函數本身有一些需要解決的問題:

sigintHandler是一個嵌套函數,因此當您的信號處理函數f通過return sigintHandler; ,您正在返回一個函數指針。

在您的代碼中,這可以正確編譯,因為您有typedef void (*sighandler_t)(int); ,它定義了一個函數指針類型,該類型可以指向具有void返回類型並以int作為參數的函數,您的sigintHandler定義為。

相反,您的信號處理函數可以簡單地編寫為:

void sigintHandler(int sig) {
    printf("Signal %d\n", sig);
}

在您的主要功能中,您有以下內容:

if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
    // ....    
}

這里應該注意這也有一些問題。 首先, signal函數將信號編號(通常是在signal.h頭文件中定義的宏)作為它的第一個參數,並將其作為第二個參數,一個指向定義為void func_name(int sig)的函數的指針。

為此,您正在調用該函數而不是將其作為指針傳遞。

*f(1)實際上調用f並傳遞1作為其參數; 相反,您可以將其更改為以下內容:

if (signal(SIGTSTP, f) == SIG_ERR) {
    // ....    
}

但這應該會發出警告/錯誤,因為f被定義為返回函數指針而不是void

因此,要將代碼更改為合規,您只需執行以下操作:

#include <stdio.h>
#include <signal.h>

void sigintHandler(int sig) {
    printf("Signal %d", sig);
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

然而你說:

要有可變的行為......

這取決於您想要什么樣的變量性質,但如果它是基於信號的變量函數,您可以執行以下操作:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sig_stop(int sig) {
    printf("Process %d stop\n", getpid());
}

void sig_int(int sig) {
    printf("Process %d interrupt\n", getpid());
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
        // ...
    }
    if (signal(SIGINT, sig_int) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

或者你可以使用switch語句:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sigHandler(int sig) {
    printf("Process %d received %d\n", getpid(), sig);
    switch (sig) {
        case SIGTSTP:
            // do stop code
            break;
        case SIGINT:
            // do interupt code
            break;
    }
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sigHandler) == SIG_ERR) {
        // ...
    }
    if (signal(SIGINT, sigHandler) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

任何有關如何調試段錯誤的提示將不勝感激!

首先,了解什么是分段錯誤 那么你可以使用像一個調試器gdb通過您的代碼步驟或檢查故障轉儲,看看那里特別是segfault的發生。

希望能有所幫助。

不確定您在問什么,但我可以幫助您了解您的分段錯誤。

當你調用一個函數時,有幾件事情要做。

  1. 將函數參數推入堆棧
  2. 將返回地址推入堆棧
  3. 跳轉到函數地址
  4. 函數體
  5. 從棧中彈出返回地址
  6. 從堆棧彈出函數參數。

當 1,2, 6 由 Calling 作用域完成時。

如您所知,signal 是一個void arguments因此調用 (1) 會將0參數壓入堆棧。

而 return (6) 將從堆棧中彈出您的“不存在的” int並破壞它。

有點解決

你不能有帶參數的信號函數,
你能做的是:

  1. 您可以在信號函數中讀取全局變量。 因此讀取程序的當前狀態。

  2. 您可以通過 sys_call 獲取您的 process_id、thread_id。

  3. 我不推薦,但您可以將堆棧進一步讀取到先前的范圍並獲取它的局部變量。 使用 BIG 請注意,它不會是您將信號設置為...的功能,而是在發出信號時正在運行的功能。

暫無
暫無

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

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