2017-06-07 214 views
-1

我創建了一個小的C程序創建一個時間戳,並將其附加到文件的文本名稱:傳遞一個函數指針作爲參數給fopen

#include <stdio.h> 
#include <time.h> 
#include <string.h> 
#include <stdlib.h> 

void time_stamp(){ 
    time_t rawtime; 
    struct tm * timeinfo; 
    char buffer [80]; 
    time (&rawtime); 
    timeinfo = localtime (&rawtime); 

    strftime (buffer,80,"myFile_%F.txt",timeinfo); 
    printf ("%s", buffer); 
} 


int main() 
{ 
    void (*filename_ptr)(); 
    filename_ptr = &time_stamp; 

    FILE * fp; 

    fp = fopen (filename_ptr, "w+"); 
    fprintf(fp, "%s %s %s %d", "We", "are", "in", 2017); 

    fclose(fp); 

    return 0; 
} 

但我不能得到的fopen接受指針該函數用時間戳創建名稱。它期望一個const char。我如何施放我的函數指針呢?

+4

你期望fopen如何處理函數指針? – Yunnosch

+1

這是因爲你的CPU沒有DWIM(我的意思是什麼)指令。在此之前,你需要實際告訴計算機該做什麼,因爲它無法讀懂你的想法。 – Art

+1

查看您的手冊或手冊頁,瞭解fopen的原型。這是你需要履行的合同。這些是你必須遵守的規則。如果有一個'const char *'作爲第一個參數,那麼你不應該傳入一些奇怪的奇特函數指針。 – Gerhardh

回答

2

你不能,但你可以通過追加()的指針調用該函數。對於這項工作,改變你的函數實際上返回const char *(或char *

注意你不能只返回一個指針到您buffer,因爲這是一個局部變量不再存在時,函數返回。您可以從函數外部傳遞指向buffer的指針。然後,您的原型應該是

char *time_stamp(char *buf, size_t len); 

修改後的代碼:

#include <stdio.h> 
#include <time.h> 
#include <string.h> 
#include <stdlib.h> 

char *time_stamp(char *buf, size_t len){ 
    time_t rawtime; 
    struct tm * timeinfo; 
    time (&rawtime); 
    timeinfo = localtime (&rawtime); 

    strftime (buf,len,"myFile_%F.txt",timeinfo); 
    return buf; 
} 


int main() 
{ 
    char *(*filename_ptr)(char *, size_t); 
    filename_ptr = &time_stamp; 
    char buffer[80]; 

    FILE * fp; 

    fp = fopen (filename_ptr(buffer, 80), "w+"); 
    fprintf(fp, "%s %s %s %d", "We", "are", "in", 2017); 

    fclose(fp); 

    return 0; 
} 

有其他方法如何設計這個功能。 Neroku當你確定你永遠不需要線程上下文中的函數時,答案是很好的。它簡化了使用,甚至還有一些標準的C庫函數。

第三種方法是通過從malloc()中獲取它來使緩衝區成爲分配的對象。這具有線程安全並且不需要任何額外參數的優點,函數本身像在原始的破碎版本中一樣控制緩衝區的大小。缺點是調用者必須使用free()這個內存。這個示例代碼(我這裏不推薦的):

#include <stdio.h> 
#include <time.h> 
#include <string.h> 
#include <stdlib.h> 

char *time_stamp(){ 
    time_t rawtime; 
    struct tm * timeinfo; 
    time (&rawtime); 
    timeinfo = localtime (&rawtime); 

    char *buf = malloc(80); 
    strftime (buf,80,"myFile_%F.txt",timeinfo); 
    return buf; 
} 


int main() 
{ 
    char *(*filename_ptr)(); 
    filename_ptr = &time_stamp; 

    FILE * fp; 

    char *filename = filename_ptr(); 
    fp = fopen (filename, "w+"); 
    free(filename); 
    fprintf(fp, "%s %s %s %d", "We", "are", "in", 2017); 

    fclose(fp); 

    return 0; 
} 
2

fopen()需要一個const char *作爲第一個參數:

FILE *fopen(const char *path, const char *mode); 

在你的函數time_stamp()打印時間戳和返回沒有,即:void


您的新time_stamp()功能可以代替(注意staticbuffer聲明):

const char* time_stamp(){ 
    time_t rawtime; 
    struct tm * timeinfo; 
    static char buffer [80]; 
    time (&rawtime); 
    timeinfo = localtime (&rawtime); 

    strftime (buffer,80,"myFile_%F.txt",timeinfo); 
    return buffer; 
} 

然後你可以呼叫在調用fopen()的時刻這一新功能。通過time_stamp()返回的值會變成的fopen()第一個參數:

const char * (*filename_ptr)(); 
filename_ptr = &time_stamp; 
// ... 
fp = fopen (filename_ptr(), "w+"); 

注意,值的類型從time_stamp()現在比賽的第一個參數的類型返回fopen()預計(即:const char *)。


註上線程安全

由於函數time_stamp()包含靜態分配存儲buffer),它是不安全的多線程程序中使用此功能,因爲所有的線程那調用此函數將共享此存儲的單個實例。

+1

不是它與OP有關,但是'static'使函數線程不安全。只是要記住;) –

+0

@FelixPalmen是的,上面的代碼是*線程不安全*,但我不爭取*線程安全*代碼。 –

+0

爲了提高答案的清晰度並部分降低重複使用以達到類似未來目的的風險,我建議將該稍有風險的假設編輯到答案中,並解釋在哪種情況下以及在哪些情況下需要使用函數以便注意安全。然而,一般來說,編寫線索函數對於編寫可以以某種方式使用的函數而言是優選的,儘管不安全。 – Yunnosch

相關問題