顺便读取内存:“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 *

当然, charunsigned 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都有相同的值,所以在这种情况下无关紧要

编辑

如果你读取任何东西作为签名字符仍然在那种情况下,大多数高位也将复制所以它无关紧要