顺便读取内存:“signed char *”vs“unsigned char *”
人们经常需要一次一个字节地读取内存,就像在这个天真的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 *
。
当然, char
和unsigned char
可能不相等。 但是,当按字节读/写内存时,我是否使用char *
, signed char *
或unsigned char *
有所不同吗?
更新:实际上,我完全清楚c=200
可能有不同的值,具体取决于c
的类型。 我在这里问的是为什么人们在读取内存时有时会使用unsigned char *
而不是char *
,例如为了在char[4]
存储uint32_t
。
你应该使用unsigned char
。 C99标准表示unsigned char
是唯一保证密集的类型(没有填充位),并且还定义了您可以通过将任何对象(除了位域)复制到unsigned char
数组中来完全复制它,该数组是对象表示forms 。字节。
对我来说明智的解释是,如果你使用指针来访问对象作为字节,你应该使用unsigned char
。
参考: http : //blackshell.com/~msmud/cstd.html#6.2.6.1 (来自C1x草案 C99)
这是C ++与C不同的一点。一般来说,C只保证原始内存访问适用于unsigned char
; char
可以被签名,并且在1的补码或有符号幅度的机器上,-0可能会自动转换为+0,从而改变位模式。 出于某种原因(我不知道),C ++委员会将支持透明复制(不改变位模式)的保证扩展为char
,以及unsigned char
; 在1的补码或有符号幅度的机器上,实现者别无选择,只能使普通char
无符号,以避免这种副作用。 (当然,今天大多数程序员都不关心这类机器。)
无论如何,最终结果是来自C背景的老程序员(可能实际上使用1的补码或签名量级的机器)将自动使用unsigned char
。 它也是一种常见的约定,它为唯一的字符数据保留普通char
,对于非常小的整数值使用signed char
,为原始内存保留unsigned char
,或者在预期进行位操作时。 这样的规则允许读者区分不同的用途(假设它被虔诚地遵循)。
在您的代码示例中,它没有任何区别。 但是如果你想显示/打印字节的值而不是(因为最高位的解释不同),而unsigned char
似乎更合适
这取决于你想要存储在char中的内容。 带符号的char给出的范围是-127到127,而unsigned char的范围是0到255。
对于指针算术,它无关紧要。
#include #include 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都有相同的值,所以在这种情况下无关紧要
编辑
如果你读取任何东西作为签名字符仍然在那种情况下,大多数高位也将复制所以它无关紧要