2013-04-27 46 views
4
  • 編譯器:GCC 4.4.5(代碼::塊)
  • 平臺:Linux內核版本2.6.32-5-686(Debian的)

我目前正在寫的是轉換字符串的函數成雙倍多頭。我知道已經有一個功能可以做到這一點。我只是寫這個功能的練習,但我目前不知道該怎麼做。如何指示錯誤,因爲所有數字都是有效的返回值?

當我的函數只能處理正雙長整數時,我的函數可以正常工作,因爲如果它們是字符串中的無效字符,我可以返回-1。但我希望這個功能能夠處理負雙倍多頭和正數。我不知道我在這種情況下應該做什麼,因爲現在所有的實數都是有效的返回值。我想通過將無效字符轉換爲十進制值,或僅僅忽略無效字符並僅挑選有效字符0-9(十進制48-57),即使無效字符存在,仍繼續進行轉換。我也想過返回一個指向雙精度長度的指針,並使用NULL地址來表示找到了一個無效的字符,或者我可以像設置功能readdir()那樣設置errno。我不知道如何設置errno或者甚至允許。所以我的問題總的來說是你們會推薦我在這種情況下做什麼?同時請注意,我沒有處理包括負雙多頭尚未和功能將完全忽略無效字符:例如$&3%7AJ89將被轉換爲3789.

double long cstrtodl(const char *cstr) 
{ 
double long power; 
double long dl = 0; 
int decimal_place; 
int bool_decimal = 0; 

for(decimal_place = 1; cstr[decimal_place] != '\0'; decimal_place++) 
{ 
    if(cstr[decimal_place] == '.') 
    { 
     bool_decimal = decimal_place; 
     break; 
    } 
} 

for(decimal_place--, power = 1; decimal_place >= 0; decimal_place--, power *= 10) 
{ 
    printf("[%i] = %i(%c)\nPOWER = %LF\nINTEGER = %LF\n", decimal_place, (int)cstr[decimal_place], cstr[decimal_place], power, dl); 
    switch(cstr[decimal_place]) 
    { 
     case 48: 
      dl += 0 * power; 
     break; 

     case 49: 
      dl += 1 * power; 
     break; 

     case 50: 
      dl += 2 * power; 
     break; 

     case 51: 
      dl += 3 * power; 
     break; 

     case 52: 
      dl += 4 * power; 
     break; 

     case 53: 
      dl += 5 * power; 
     break; 

     case 54: 
      dl += 6 * power; 
     break; 

     case 55: 
      dl += 7 * power; 
     break; 

     case 56: 
      dl += 8 * power; 
     break; 

     case 57: 
      dl += 9 * power; 
     break; 

     default: 
      power /= 10; 
     break; 
    } 
} 

if(bool_decimal > 0) 
{ 
    for(decimal_place = bool_decimal+1, power = 10; cstr[decimal_place] != '\0'; decimal_place++, power *= 10) 
    { 
     printf("[%i] = %i(%c)\nPOWER = %LF\nINTEGER = %LF\n", decimal_place, (int)cstr[decimal_place], cstr[decimal_place], power, dl); 
     switch(cstr[decimal_place]) 
     { 
      case 48: 
       dl += 0/power; 
      break; 

      case 49: 
       dl += 1/power; 
      break; 

      case 50: 
       dl += 2/power; 
      break; 

      case 51: 
       dl += 3/power; 
      break; 

      case 52: 
       dl += 4/power; 
      break; 

      case 53: 
       dl += 5/power; 
      break; 

      case 54: 
       dl += 6/power; 
      break; 

      case 55: 
       dl += 7/power; 
      break; 

      case 56: 
       dl += 8/power; 
      break; 

      case 57: 
       dl += 9/power; 
      break; 

      default: 
       power /= 10; 
      break; 
     } 
    } 
} 

return dl; 
} 
+0

是完全允許如何在不可分析輸入的情況下返回喃? – wildplasser 2013-04-27 14:15:06

+0

@wildplasser我不認爲C有NaNs。 – michaelb958 2013-04-27 14:17:59

+1

通常實現的浮點類型有,但我投票設置'errno'。 – 2013-04-27 14:20:53

回答

5

返回一個指針是複雜和低效的,因爲你必須要malloc一個緩衝區然後reme mber到free吧。返回一個簡單的,固定大小的值會帶來很多開銷。相反,你可以返回一個狀態代碼,並將結果寫入指針:

// returns zero on success, -1 on error 
int cstrtodl(const char *cstr, long double *result); 

爲了某些目的,它也可能是有用的知道有多少串的消耗,如果你沒有一定閱讀所有的。在這種情況下,您可以返回size_tssize_t,並且返回0(錯誤消失)或錯誤-1。然後調用者可以檢查輸入字符串中的數字是否有任何意外。

設置errno在C.

+0

所以你說我應該返回從字符串中讀取的字符數,並使用雙長指針來傳遞雙長字符? – 2013-04-27 14:31:55

+0

@JohnVulconshinz:這就是我要做的事情,以及許多圖書館做的事情。如果你不關心讀取的字符數量,那麼一個簡單的'int'類型的錯誤代碼就足夠了。 – 2013-04-27 14:34:32

+1

這個答案提出了最習慣的C設計。 +1 – user4815162342 2013-04-27 14:42:22

1

我建議要麼返回一個指針所得到的在錯誤時爲double或NULL(如你所建議的),或者如strtoul(),添加一個指向第一個未轉換字符的指針參數。

至於errno,它只是另一個全局變量(只是碰巧在libc中聲明),並且將自己的值分配給它是很好的。

+2

你將如何返回一個指向結果的指針?您必須爲其分配存儲空間,引入新的無意義的失敗原因,或要求調用方向您傳遞存儲結果位置的指針。 – 2013-04-27 14:24:48

4

您有幾種選擇:

  1. 使用NAN作爲一個錯誤值。請記住,您無法使用==檢查NAN。您必須使用isnan(x)x!=x來檢查x是否爲NAN。

  2. 增加一個額外的int *errorp參數來存儲標誌(可能是錯誤代碼)是否發生錯誤。該選項有兩個子選項:您可能想要成功寫入0,或者您可能希望單獨保留以前的內容,以便呼叫者可以進行多次呼叫,並且只在最後檢查是否其中任何一個失敗。

  3. 切換東西:將指針傳遞到存儲結果的位置,並將返回值用於錯誤代碼。這種方法鼓勵在每次調用之後檢查錯誤,但是很難直接在表達式中使用結果,這可能很煩人。

  4. 通過特殊的線程本地狀態報告錯誤:errno,浮點異常標誌(警告:某些機器不支持fenv/exceptions!)或您自己的線程本地對象。根據你的觀點,這可能是錯誤/醜陋的,因爲它是一個隱藏的信息頻道,但它也可以是最方便的來電者。

  5. 通過全局狀態報告錯誤。請不要這樣做。它排除了多線程和乾淨的庫對代碼的使用。

2

errno可用於此。您需要#include <errno.h>才能使用它。您可以設置errno一些預定義的值,然後調用者檢查它:

errno = 0; 
cstrtodl(some_string); 
if (errno != 0) { 
    // Error occured. 
} 

注意errno是線程安全的。如果您在一個線程中寫入該值,則其他線程中的值不會更改。所以它不只是一些全局變量。它甚至可以不是一個變量,而是內部編譯器的魔力。但重點是,你可以把它看作是一個線程局部變量。

另一種方式是通過錯誤的額外的參數:

double long cstrtodl(const char *cstr, int *error) 
{ 
    // ... 
    if (error != NULL) { 
     if (some_error_occured) { 
      *error = SOME_CONSTANT_OR_MACRO; 
     } else { 
      *error = 0; 
     } 
    } 
} 

調用者然後可以這樣做:

int error; 
cstrtodl(some_string, &error); 
if (*error) { 
    // Error occured. 
} 

或者,如果主叫方不感興趣:

cstrtodl(some_string, NULL); 
+0

我認爲你的意思是'&error'。 – 2013-04-27 14:34:52

相關問題