【问题标题】:Bytewise reading of memory: "signed char *" vs "unsigned char *"内存的字节读取:“signed char *”与“unsigned char *”
【发布时间】:2012-01-13 05:21:50
【问题描述】:

通常需要一次从内存中读取一个字节,就像在这个幼稚的 memcpy() 实现中一样:

void *memcpy(void *dest, const void *src, size_t n)
{
    char *from = (char *)src;
    char *to   = (char *)dest;

    while(n--) *to++ = *from++;

    return dest;
}

但是,我有时会看到人们明确使用 unsigned char * 而不仅仅是 char *

当然,charunsigned char 可能不相等。但是在按字节读取/写入内存时,使用char *signed char *unsigned char * 是否有区别?

更新:实际上,我完全知道c=200 可能具有不同的值,具体取决于c 的类型。我在这里要问的是为什么人们有时在读取内存时使用unsigned char * 而不仅仅是char *,例如为了将uint32_t 存储在char[4] 中。

【问题讨论】:

  • “但它有什么不同吗?” - 有什么区别?
  • 米奇:好点子,现在已经修好了。
  • unsigned char 更清楚地表示处理的是原始字节,而不是字符,即使二进制值相同并不重要。

标签: c++ c coding-style char unsigned-char


【解决方案1】:

您应该使用unsigned char。 C99 标准规定 unsigned char 是唯一保证密集(无填充位)的类型,并且还定义您可以通过将任何对象(位域除外)复制到 unsigned char 数组中来精确复制它,即 对象表示,以字节为单位。

对我来说,明智的解释是,如果您使用指针以字节形式访问对象,则应使用unsigned char

参考:http://blackshell.com/~msmud/cstd.html#6.2.6.1(来自 C1x 草稿 C99)

【讨论】:

    【解决方案2】:

    这是 C++ 与 C 不同的一点。一般来说,只有 C 保证原始内存访问适用于unsigned charchar 可能 有符号,并且在 1 的补码或有符号幅度机器上,-0 可能会自动转换为 +0,从而更改位模式。为了 出于某种原因(我不知道),C++ 委员会扩展了保证 支持透明复制(位模式不变)到char,如 还有unsigned char;在 1 的补码或有符号幅度上 机器,实现者别无选择,只能说清楚char 未签名,以避免此类副作用。 (当然,大多数 今天的程序员无论如何都不关心这些机器。)

    不管怎样,最终的结果是那些来自 C 语言的老程序员 背景(并且可能实际上已经在 1 的补码或 签名幅度机)将自动使用unsigned char。它是 也是为字符数据保留纯 char 的常见约定 唯一的是,signed char 用于非常小的整数值,并且 unsigned char 用于原始内存,或用于位操作。 这样的规则允许读者区分不同的用途 (只要虔诚地遵循它)。

    【讨论】:

    • +1,尤其是最后一部分,我一直看到unsigned chars 与“原始内存”相关联。
    • 我想每次你在上面说“2的补码”时,你的意思是“1的补码”。但它也是在 C 中实现定义的,对于 2 的补码类型,由符号位 1 和所有其他位 0 组成的值是否是陷阱值(如果不是,那么它当然是该类型的最小值)。因此,如果 char 被签名,甚至可能有一些 2 的补码硬件在某处由 char 复制将失败。
    • 我会加倍史蒂夫杰索普。我们现在都使用 2 的补码机器
    • @SteveJessop 是的。它开始是一个错字,它被重复了。 (但我从未见过陷入最大负值的 2 的补码机器。虽然这会使生活变得更轻松:-INT_MIN 不是int 的合法值这一事实意味着您必须支付在转换例程中得到很多关注。)
    • 感谢您的详尽回答!这正是我正在寻找的(我曾经读过关于 1 的补码的问题,但已经忘记了)。
    【解决方案3】:

    在您的代码示例中没有区别。但是如果你想显示/打印字节的值而不是它(因为最高位的解释不同),unsigned char 似乎更合适

    【讨论】:

      【解决方案4】:

      这取决于你想在 char 中存储什么。 有符号字符的范围是 -127 到 127,而无符号字符的范围是 0 到 255。

      对于指针运算没关系。

      【讨论】:

        【解决方案5】:
        #include<stdio.h>
        #include<string.h>
        
        int main()
        {
        
        unsigned char a[4]={254,254,254,'\0'};
        unsigned char b[4];
        char c[4];
        
        memset(b,0,4);
        memset(c,0,4);
        
        memcpy(b,a,4);
        memcpy(c,a,4);
        int i;
        for(i=0;i<4;i++)
        {
            printf("\noriginal is %d",a[i]);
            printf("\nchar %d is %d",i,c[i]);
            printf("\nunsigned char %d is %d \n\n",i,b[i]);
        }
        
        }
        

        输出是

        original is 254
        char 0 is -2           
        unsigned char 0 is 254 
        
        
        original is 254
        char 1 is -2
        unsigned char 1 is 254 
        
        
        original is 254
        char 2 is -2
        unsigned char 2 is 254 
        
        
        original is 0
        char 3 is 0
        unsigned char 3 is 0 
        

        所以这里 char 和 unsign 都具有相同的值,所以在这种情况下无关紧要

        编辑

        如果您将任何内容读取为已签名的字符,那么在这种情况下,最高位也会被复制,所以没关系

        【讨论】:

        • 我不会对其他答案投反对票,但是proof by one working example 不是与 C 一起使用的一种方式,那么我们只是在谈论一种实现,更糟糕的是,也许只是它的那个版本.
        • @kaizer.s我也不想鼓励您对此投反对票,只是一般性评论。
        • @Christian:我不明白你的观点。总的来说,我认为堆栈上的反对票太少,很少有人这样做,如果我弃权一次,也不会发生什么奇怪的事情。
        • @kaizer.se 我不是说你应该这样做,这当然是你的决定,只是不要因为错误的原因(比如政治正确或诸如此类)而克制它,这会使投票系统变得荒谬。
        猜你喜欢
        • 2012-09-27
        • 2012-04-11
        • 2017-03-27
        • 1970-01-01
        • 2011-07-02
        • 2023-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多