代码之家  ›  专栏  ›  技术社区  ›  ChristopheD

这是将long转换为二进制(char*)表示的惯用C方式吗?

  •  2
  • ChristopheD  · 技术社区  · 16 年前

    我想问题就在标题里。

    这是我提出的临时解决方案,但我想知道:

    • 如果将二进制表示为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;
    }
    
    8 回复  |  直到 16 年前
        1
  •  7
  •   Steve Jessop    16 年前

    在我看来,这个循环基本上是惯用的,只是我写的循环类似于:

    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无关,因为它是gcc方言。但即使没有它,您也不需要浮点数学来计算需要多少位数:

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

    刚刚注意到该行中也有一个可能的错误-您的do/while循环巧妙地处理了以下情况: input 是0,但第一行没有,因为您无法获取0的日志。

    有没有更好的方法(考虑到我想要位移位的能力等…)

    不知道你在这里是什么意思。如果您想对值进行位移位之类的操作,那么不要将其转换为这样的字符串。把它当作一本书 long int ,然后在那里做你的工作。

    其他小事情,因为你在征求一般意见。只要你有理由这么做,这些都不是我真正要批评的:

    • 所需数字 ),只是噪音。
    • 我总是会立即检查malloc(或任何其他返回错误值的函数)的返回值,而不是中间有一行代码。所以,移动 int idx = needed_digits 排到“做…”之前。。while'循环(因为您使用的是std=c99。如果是c89,那么您仍然可以这样做,除了我要推荐的…)。
    • 我不会在有条件退出或返回后加上“else”。但是其他人也会像你一样,争论可能会变得很激烈。
    • 就我个人而言,我不会乘 sizeof(char) 在malloc中,由于malloc分配的缓冲区大小定义为以字符为单位。但是其他人把它放在那里,所以每个malloc始终都有一个sizeof,所以我不能说我的方式是惯用的。只是更好;-)

    对于最后三件事中的每一件,好的C编程实践不一定要像我这样做,而是要与您的同事/合作者商定一种编码风格。只要你们同意不争论,不“整理”彼此的代码,编码标准就可以是“随心所欲”。

        2
  •  4
  •   Bastien Léonard    16 年前

    不需要将数字转换为二进制表示;它们已经在内存中的二进制文件中表示。

    #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');
    }
    
        3
  •  3
  •   Matthew Iselin    16 年前
    itoa(value, output_buffer, base);
    

    有更好的办法吗 “,而不是问题的任何其他部分。

    编辑:另外,您可能想看看流行的itoa实现,看看它们是如何在不需要数学函数的情况下实现多基转换的(来自-lm)。我知道我见过的很多itoa都非常小巧、优雅,而且仍然非常强大。

        4
  •  3
  •   Community Mohan Dere    8 年前

    Customizing printf

    然后你可以做:

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

    这比在函数中调用printf()更灵活。

    您仍然需要指定一个函数来进行转换;但是,您可以在整个代码中使用printf。

    Bastien Lonard的答案有一个更惯用的函数来进行转换,使用按位and代替模2,用位移位代替除法,用三值运算符代替if else。

    这是一个相关的问题:

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

        5
  •  2
  •   saxi    16 年前

    好的,使用查找表的另一种可能的解决方案:

    #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:我只检查小端的内存组织。

        6
  •  2
  •   Matt Bridges    16 年前

    您转换为(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;
        }
    }
    
        7
  •  1
  •   Emil H    16 年前

    还有另一种选择。这只是循环从最高有效位到最低有效位的所有位,并检查它们是否已设置。

    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');
    }
    

    这没有做任何其他人没有提出过的事情。对我来说,这只是一种更容易记住的方法。

        8
  •  1
  •   Norman Ramsey    16 年前

    我们把最重要的数字放在第一位,这是阿拉伯语符号的一大悲剧。当我们从最低有效数字开始时,几乎所有的计算都更容易:

    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");
    }
    

    如果你曾经为图灵机编写过代码(学生练习,不实用),那么关于表示的注释就会加倍。