2009-08-09 43 views
2

問題出在標題我猜。這是一個慣用的C方式將long轉換爲二進制(char *)表示形式嗎?

這是我想出了一個臨時的解決方案,但我想知道:

  • 如果有缺點表示二進制爲char *。有沒有更好的方法(考慮我想要位移等的能力......)
  • 如果在下面的代碼中存在明顯的非慣用C(或其他錯誤)。

所有的建議表示歡迎...

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

/* compile with 
    gcc -lm -std=c99 
*/ 

void binary_repr(unsigned long input) { 
    int needed_digits = (int) (floor(log2(input)) + 1); 
    char *ptr_binarray = malloc((needed_digits + 1) * sizeof (char)); 
    int idx = (needed_digits); 

    if (ptr_binarray == NULL) { 
      printf("Unable to allocate memory."); 
     exit(1); 
    } 
    else { 
     do { 
      idx--; 
      if (input % 2 == 0) { 
       ptr_binarray[idx] = '0'; 
      } 
      else { 
       ptr_binarray[idx] = '1'; 
      } 
      input = input/2; 

     } while (input > 0); 

     ptr_binarray[needed_digits] = '\0'; 
     printf("%s\n", ptr_binarray); 
     free(ptr_binarray); 
     ptr_binarray = NULL; 
    } 
} 

int main() 
{ 
    binary_repr(8); 
    binary_repr(14); 
    binary_repr(4097); 
    return 0; 
} 
+0

'x * sizeof(char)'可以只是'x',因爲'sizeof(char)'是1的定義。 – 2009-08-10 02:17:42

+0

我不會稱之爲「慣用」的東西那麼大:) – qrdl 2009-08-10 06:47:36

回答

7

看起來大約慣用的我,只是我會寫循環類似:

char *writeptr = ptr_binarray + needed_digits; 
*writeptr = 0; 
do { 
    --writeptr; 
    *writeptr = (input % 2) + '0'; 
    input /= 2; 
} while (input > 0); 

無需整數索引。

對於這個特殊情況,我不會打擾malloc,因爲你free在同一個函數。就在棧上分配一個足夠大的字符數組:

char binarray[sizeof(unsigned long)*CHAR_BIT + 1]; 

或使用C99的可變長數組:

char binarray[needed_digits + 1]; 

另外,如果你只使用gcc,然後而不是採取對數你可以考慮使用__builtin_clz來計算needed_digits。這不是關於慣用的C,因爲它是海灣合作委員會的方言。但即使沒有它,你並不需要浮點運算,計算出有多少位需要:

http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious

該行只注意到一個可能的錯誤,太 - 你的do/while循環整齊地處理input爲0的情況,但第一行沒有,因爲你不能取0的日誌。

有沒有更好的辦法(考慮到我希望的能力比特移位等)

不知道你的意思在這裏。如果你想對一個值做位移操作,那麼不要把它轉換成像這樣的字符串。保留它作爲long int,並在那裏做你的位移。

其他小事情,因爲你要求的一般意見。這些都不是的東西我真的批評,只要你有你做他們一個理由:

  • 刪除無意義的括號左右(needed_digits),它只是噪音。
  • 錯誤消息應該可能轉到stderr而不是stdout。
  • 我會一直檢查malloc(或任何其他返回錯誤值的函數)的返回值,而不是在它們之間有一行代碼。因此,將int idx = needed_digits行下移到'do .. while'循環之前(因爲您使用的是std = c99。如果是c89,那麼除了我會推薦...之外,您仍然可以這樣做) 。
  • 在條件退出或返回後,我不會放置「else」。但其他人會像你一樣做,而且這個論點可能會變得部落。
  • 就我個人而言,我不會在malloc中乘以sizeof(char),因爲malloc分配的緩衝區的大小按字符的定義來衡量。但是其他人把它放在那裏,以便每個malloc始終有一個sizeof,所以我不能說我的方式是慣用的。它只是更好;-)
  • 自由之後清除指針可以說是值得的,當他們在一個結構,但不是自動化。

對於最後三件事情,好的C編程習慣並不一定像我這樣做,而是要與同事/合作者達成一致的編碼風格。編碼標準允許「只要你喜歡」,只要你同意不爭論,而不是「整理」彼此的代碼。

+0

+1 - 深度很好,代碼示例也很乾淨優雅。 – 2009-08-10 00:12:24

+0

完美!這正是我正在尋找的答案。如果明天晚上有空閒時間,我會嘗試更新有問題的代碼。 – ChristopheD 2009-08-10 20:10:13

3

您可以使用glibc的註冊自定義的printf轉換說明:

Customizing printf

然後,你可以這樣做:

printf("Binary Representation: %b\n", num); 

這會更靈活而不是在你的函數中調用printf()。

您仍然需要指定一個函數來完成轉換;但是你可以在整個代碼中使用(s)printf。

BastienLéonard的答案有一個更習慣的功能來完成轉換,使用按位而不是模2,位移而不是除法,以及三元運算符而不是其他。

這裏有一個相關的問題:

is-there-a-printf-converter-to-print-in-binary-format

3
itoa(value, output_buffer, base); 

如果您使用2作爲base,您將在字符串中獲得二進制版本。

請注意,我只回答「有沒有更好的方法」,而不是問題的任何其他組成部分。

編輯:另外,你可能想看看itoa的流行實現,看看他們如何做多基地轉換,而不需要數學函數(從-lm)。我知道我見過的很多itoa都非常小巧優雅,而且還非常強大。

+1

有趣,我從來沒有見過itoa()。那是什麼標準? – 2009-08-09 23:24:39

+0

我不認爲itoa()是標準的。 – 2009-08-09 23:27:29

+0

http://en.wikipedia.org/wiki/Itoa,「itoa函數是對標準C編程語言的廣泛的非標準擴展」。 – 2009-08-09 23:27:38

2

您是否正在轉換爲(char *),因爲您想要位移的能力?如果是這樣,你是否知道移位運算符?

short int n = 1; //0x0001 
n = n << 1;  //shift bits 1 place to the left 
        //n is now 2; 0x0010 

只是爲了笑聲,這裏使用移位操作打印的二進制表示的例行:

void printbitssimple(int n) { 
    unsigned int i; 
    i = 1<<(sizeof(n) * 8 - 1); 

    while (i > 0) { 
     if (n & i) 
      printf("1"); 
     else 
      printf("0"); 
     i >>= 1; 
    } 
} 
+0

嗯,基本上我想將長整型轉換爲char *以用二進制乘法(產品比長數據類型限制大)進行播放。我應該在我的問題中包含這些信息。感謝您花時間回答(和洞察)​​! – ChristopheD 2009-08-10 20:14:23

4

沒有必要爲數字「轉換」成二進制表示;它們已經在二進制內存中表示。 使用位運算符它很容易用二進制表示玩:

#include <limits.h> 
#include <stdio.h> 

static void binary_repr(unsigned long input); 

int main (void) 
{ 
    binary_repr(0); 
    binary_repr(1); 
    binary_repr(16); 

    return 0; 
} 

static void binary_repr(unsigned long input) 
{ 
    unsigned int i; 
    unsigned int nb_bits = sizeof(input) * CHAR_BIT; 

    for (i = 0; i < nb_bits; ++i) 
    { 
     /* print the left-most bit */ 
     putchar((input & (1 << (nb_bits - 1))) == 0 ? '0' : '1'); 
     /* left-shift by onex */ 
     input <<= 1; 
    } 

    putchar('\n'); 
} 
+0

非常好,簡潔的方式。非常感謝! – ChristopheD 2009-08-10 20:11:07

1

另一個選擇。這只是簡單地遍歷從最重要到最不重要的所有位,並檢查它們是否被設置。

void binary_repr(unsigned long input) 
{ 
    int i = sizeof(input) * 8 - 1; 
    for (; i >= 0; --i) { 
     putchar((input & (1 << i)) == 0 ? '0' : '1'); 
    } 

    putchar('\n'); 
} 

這不會做任何尚未被其他人在這裏建議的任何事情。這只是一種更容易記住的方法。

2

好,使用查找表中的另一個可能的解決方案:

#include <stdio.h> 

#undef BIGENDIAN 

#ifdef BIGENDIAN 
enum { TSIZE = sizeof(int), INIT = 0, END = TSIZE }; 
#define op(x) ++(x) 
#define cond(x) ((x) < END) 

#else 
enum { TSIZE = sizeof(int), INIT = TSIZE - 1, END = -1 }; 
#define op(x) --(x) 
#define cond(x) ((x) > END) 

#endif 

static char *binstr[] = { 
    "0000", // 0x0 
    "0001", // 0x1 
    "0010", // 0x2 
    "0011", // 0x3 
    "0100", // 0x4 
    "0101", // 0x5 
    "0110", // 0x6 
    "0111", // 0x7 
    "1000", // 0x8 
    "1001", // 0x9 
    "1010", // 0xA 
    "1011", // 0xB 
    "1100", // 0xC 
    "1101", // 0xD 
    "1110", // 0xE 
    "1111", // 0xF 
}; 


int main(void) 
{ 
    int num, i; 
    unsigned char *hex; 

    hex = ((unsigned char *) &num); 
    while(fscanf(stdin, "%i", &num) != EOF) 
    { 
    for(i = INIT; cond(i); op(i)) 
     printf("%s%s", binstr[hex[i]>>4], binstr[hex[i]&0xF]); 
    printf("\n"); 
    } 

    return 0; 
} 

PD:我只跟小端存儲器組織檢查。

+0

不錯的替代解決方案,謝謝! – ChristopheD 2009-08-10 20:15:45

1

這是阿拉伯符號的最大悲劇之一,我們把最重要的數字放在第一位。

void fprint_binary(FILE *fp, unsigned long n) { 
    char digits[8*sizeof(n)+1]; 
    char *p = digits+sizeof(digits)-1; 
    *p = '\0'; 
    unsigned long mask; 
    for (mask = 1; mask; mask <<= 1) 
    *--p = mask & n ? '1' : '0'; 
    while (*p == '0') 
    p++; 
    fprintf(fp, "%s", *p ? p : "0"); 
} 

有關代表的意見去雙如果你曾經編寫代碼圖靈機(練習生,不實用):幾乎所有的計算,當我們開始用最少的顯著數字更容易。

+0

不錯的代碼,謝謝! – ChristopheD 2009-08-10 20:15:09

相關問題