【问题标题】:How can I copy 4 letter ascii word to buffer in C?如何将 4 个字母的 ascii 字复制到 C 中的缓冲区?
【发布时间】:2017-06-15 21:25:01
【问题描述】:

我正在尝试将单词:0x0FF0 复制到缓冲区,但无法这样做。
这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>


void print_bits(unsigned int x);

int main(int argc, char *argv[])
{


    char buffer[512];

    unsigned int init = 0x0FF0;
    unsigned int * som = &init;

    printf("print bits of som now: \n");
    print_bits(init);
    printf("\n");

    memset(&buffer[0], 0, sizeof(buffer)); // reinitialize the buffer
    memcpy(buffer, som, 4); // copy word to the buffer

    printf("print bits of buffer[0] now: \n");
    print_bits(buffer[0]);
    printf("\n");


    return 0;
}

void print_bits(unsigned int x)
{
    int i;
    for (i = 8 * sizeof(x)-17; i >= 0; i--) {
        (x & (1 << i)) ? putchar('1') : putchar('0');
    }
    printf("\n");
}  

这是我在控制台中得到的结果:

如果我使用 memcpy,为什么我会从位打印中得到不同的值?

不知道它是否与 big-little-endian 有关,但我在这里丢失了 4 位 1,所以在这两种方法中都不应该发生。

【问题讨论】:

  • 不要发布文字图片!
  • 不要使用幻数! sizeof(unsigned int) 不保证是 4,分别。 32 位。而且代码太复杂了。在您的平台上,char 的签名是哪个?多少位?

标签: c buffer ascii memcpy


【解决方案1】:

当你打电话时

print_bits(buffer[0]);

您只从缓冲区中取出一个字节,将其转换为unsigned int,并将其传递给函数。 buffer 中的其他字节将被忽略。

【讨论】:

    【解决方案2】:

    您正在混淆类型并依赖于您的架构/平台的特定设置;这已经破坏了您现有的代码,并且一旦您使用不同的设置进行编译,它可能会变得更加有害。

    你的缓冲区是 char[512] 类型,而你的 init 是 unsigned int 类型。 首先,char 是有符号字符还是无符号字符取决于设置。这实际上是相关的,因为它会影响将 char 值提升为无符号 int 值的方式。请参阅以下代码,该代码使用显式签名和无符号字符演示了差异:

    signed char c = 0xF0;
    unsigned char uc = c;
    unsigned int ui_from_c = c;
    unsigned int ui_from_uc = uc;
    
    printf("Singned char c:%hhd; Unsigned char uc:%hhu; ui_from_c:%u ui_from_uc:%u\n", c, uc, ui_from_c,ui_from_uc);
    // output: Singned char c:-16; Unsigned char uc:240; ui_from_c:4294967280 ui_from_uc:240
    

    其次,int 可以用 4 个或 8 个字节表示(可以保存一个“字”),而char 通常是 1 个字节,因此不能保存一个 16 位的“字”。 第三,架构可以是大端或小端,这会影响像 0x0FF0 这样需要 2 个字节的常量在 4 或 8 字节整数表示中的实际位置。

    所以可以肯定的是,buffer[0] 只选择了你认为它所做的部分,这部分可能会以错误的方式提升为无符号整数,甚至可能是完全超出 @ 的部分987654329@-literal.

    我建议使用固定宽度的整数值来完全代表一个单词:

    #include <stdio.h>
    #include <stdint.h>
    
    void print_bits(uint16_t x);
    
    int main(int argc, char *argv[])
    {
    
    
        uint16_t buffer[512];
    
        uint16_t init = 0x0FF0;
        uint16_t * som = &init;
    
        printf("print bits of som now: \n");
        print_bits(init);
        printf("\n");
    
        memset(buffer, 0, sizeof(buffer)); // reinitialize the buffer
        memcpy(buffer, som, sizeof(*som)); // copy word to the buffer
    
        printf("print bits of buffer[0] now: \n");
        print_bits(buffer[0]);
        printf("\n");
    
    
        return 0;
    }
    
    void print_bits(uint16_t x)
    {
        int i;
        for (i = 8 * sizeof(x); i >= 0; i--) {
            (x & (1 << i)) ? putchar('1') : putchar('0');
        }
        printf("\n");
    }
    

    【讨论】:

      【解决方案3】:

      您没有将字节“0F F0”写入缓冲区。您正在编写平台内部使​​用的任何字节来存储数字 0x0FF0。没有理由这些必须相同。

      当您在 C 中编写 0x0FF0 时,大致意思是“无论我的实现使用什么来编码四千八十”。那可能是字节串 0F, F0。但可能不是。

      我的意思是,如果unsigned int init = 0x0FF0;unsigned int init = 4080; 在某些平台上做同样的事情而在其他平台上做不同的事情,那该有多奇怪?但肯定不是所有平台都使用字节串“0F F0”存储数字 4,080。

      例如,我可以将 number 十存储为“10”或“十”或任何其他方式。仅仅因为您存储了数字 10,您就期望“十”、“10”或任何其他特定的字节序列出现在内存中是不合理的,除非您确实恰好知道您的平台如何存储数字 10。既然你问了这个问题,你就不知道了。

      另外,您只打印了buffer[0] 的值,它是单个字符。所以它不可能拥有任何版本的 0x0FF0。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-17
        • 2015-10-29
        • 2010-09-27
        • 2016-07-26
        • 1970-01-01
        • 2012-08-15
        • 2021-12-31
        • 1970-01-01
        相关资源
        最近更新 更多