2015-06-12 23 views
3

我正在爲C中的趣味/練習編寫通用交換函數genericSwap()。 (讓我們拋開這個問題是否是個好主意。)由於函數內部使用了memcpy(),我需要處理指針通過的情況,這些指針是NULL,在所有其他關於通用交換函數的問題中,這個問題似乎被忽略了。下面是我如何做到這一點至今:處理通用交換函數中的NULL指針

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

void genericSwap(void *x, void *y, size_t size); 

int main(void) 
{ 
     int num1; 
     int num2; 

     num1 = 1; 
     num2 = 2; 

     printf("%d\t%d\n", num1, num2); 

     genericSwap(&num1, &num2, sizeof(num1)); 

     printf("%d\t%d\n", num1, num2); 

     exit(EXIT_SUCCESS); 
} 

void genericSwap(void *x, void *y, size_t size) 
{ 
     void *temp; 

     if (!x || !y) { 
       fprintf(stderr, "Trying to pass NULL pointer\n"); 
       exit(EXIT_FAILURE); 
     } 

     temp = malloc(size); 
     if(!temp) { 
       fprintf(stderr, "Memory allocation failed\n"); 
       exit(EXIT_FAILURE); 
     } 

     memcpy(temp, x, size); 
     memcpy(x, y, size); 
     memcpy(y, temp, size); 

     free(temp); 
} 

這與(當然奇怪的)情況下,像genericSwap(NULL, NULL, sizeof(something))等交易。正如你可以看到的(或者如果你喜歡測試),當NULL指針被傳遞時,該函數當前殘酷地錯誤輸出。這可能並不總是處理這種情況的首選方式。有時在一個程序中,我可能希望該功能悄悄地將控制返回給在這種情況下爲main()的呼叫者。我的想法是每個錯誤處理if -condition使genericSwap()成爲後使用空return

void genericSwap(void *x, void *y, size_t size) 
{ 
     void *temp; 

     if (!x || !y) { 
       fprintf(stderr, "Trying to pass NULL pointer\n"); 
       return; 
     } 

     temp = malloc(size); 
     if(!temp) { 
       fprintf(stderr, "Memory allocation failed\n"); 
       return; 
     } 

     memcpy(temp, x, size); 
     memcpy(x, y, size); 
     memcpy(y, temp, size); 

     free(temp); 
} 

我的問題是,如果我列出迄今爲止策略可以認爲是安全的。另外,我想聽聽你對如何改進這些功能的錯誤處理的建議。

+1

看起來更像是http://codereview.stackexchange.com/的問題嗎? – danielfranca

+2

您可以從函數中返回成功值,而不是'void',然後在main中檢查它。然後在頂層處理它。 –

+0

@danielfranca這是有點邊界線。這裏有一個改進錯誤處理的具體目標,我認爲這個問題可能同時適用於SO和CR。 –

回答

1

這裏沒有魔法。即使在自定義「庫」功能中,傳遞廢話數據通常也是未定義的行爲。打印一些東西是一個總的非起動器(例如,stderr可能會被關閉)。

如果您想要進行健全性檢查,您可以使用assert() - 編譯器在生成生產(即非開發代碼)時可以忽略/忽略這些內容,並導致相關程序崩潰,通常會提供更好的快照其狀態,包括回溯顯示它如何到達那裏。

+2

這個答案與這個問題的關係對我來說幾乎不可見。 –

+0

OP有一個奇怪的想法,就是爲他的功能「處理」不正確的參數。我說這很奇怪,說他可以做什麼,而不是他真的想檢查這些東西。 –

+0

當然,NULL是由許多函數處理的,但只有在有任何有意義的方式來執行它時(例如它表示沒有可選參數)。這裏顯然將NULL顯示爲不可接受的參數,並且OP嘗試將fprintf廢話記錄到stderr中來記錄它。這是完全錯誤的方法。 –

1

由於函數內部使用的memcpy()我需要處理,其中指針傳遞是空的情況下

爲什麼?

我的意思是,它不是錯誤要做到這一點,但你說的是參數檢查,而不是實際的功能。只是簡單地說明你的函數的行爲只有在指針參數是指向指定大小的對象表示的有效指針時才被定義是不合理的。您無法測試指示對象的大小是否正確,也不能測試指針參數是否無效,因此無論如何都不能執行完整的參數檢查。因爲這樣,似乎有點奇怪的是將NULL指針作爲特殊情況來捕捉。當我在它的時候,只要你的目標是C99或更高版本,並且你不需要支持交換巨大的對象,你可以通過一個變量在棧上分配臨時空間來獲得更好的性能-length陣列,比你通過在堆中分配它:

void genericSwap(void *x, void *y, size_t size) 
{ 
    unsigned char temp[size]; 

    memcpy(temp, x, size); 
    memcpy(x, y, size); 
    memcpy(y, temp, size); 
} 
+0

謝謝。 「你不能測試指針的大小是否正確,也不能測試指針參數是否無效,儘管它們不是NULL。」我知道我無法檢查參照物的大小。你能舉一個例子,指針參數儘管非NULL是無效的嗎?我猜他們什麼時候有不同的類型。 –

+0

如果指針參數從未被初始化(這種情況不一定產生NULL指針),或者它們曾經是有效的指針,但它們指向的內存已經被釋放,則它們可能是無效的,儘管它們是非NULL的。 –

+0

因此,遵循你的論點,你會放棄對非NULL指針的參數進行if檢查,因爲不是所有可能出錯的情況都可以檢查,只檢查malloc()。 –

0

取而代之的是「殘酷的退出」,你可以聲明功能int genericSwap(…)和返回TRUEFALSE(1或0)取決於成功。呼叫者現在可以執行以下操作並決定是否退出或以某種方式恢復:

if (!GenericSwap(p1, p2, sizeof(*p1))) { // handle error 
+0

考慮到C99,你也可以使用''和'bool'和'true'或'false'。 –