2009-08-09 71 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

相关问题