为什么字符缓冲区内容大小是 4 个字节?

董总

我调用从套接字接收数据的 recv() 并通过十六进制打印缓冲区内容的结尾

char nbuff[BUFSZ];
while ((r_n=recv(sfd,rbuff,B_BUF,MSG_EOF))>-1)
{
    printf("r_n:%d eob_p:%x\n",r_n,rbuff[r_n-1]);
    if (r_n==0)
    {
        break;
    }
    memset(rbuff,0,B_BUF);
}

结果是

r_n:1674 eob_p:3c
r_n:1228 eob_p:76
r_n:2456 eob_p:ffffff81
r_n:1228 eob_p:4b
r_n:1228 eob_p:49
r_n:2456 eob_p:57
r_n:1417 eob_p:ffffff82

我很困惑为什么结果是 4 个字节。我创建了另一个代码来打印从 buff 保存的文件

int main ()
{
    char buff[11686];
    memset(buff,0,11686);
    FILE *in =fopen("web/www.sse.com.cn.html","r");
    fread(buff,11686,1,in);
    for (int i = 0; i <  11686 ; i++)
    {
        printf("%x\n",buff[i]);
    }
}

结果是

....
buff[11684]:60
buff[11685]:ffffff82

为什么 char buff 的内容大小是 4 字节buff[11685]:ffffff82

乔纳森·莱夫勒

诊断

在第二个示例中,buff是一个char缓冲区,plainchar是您机器上的有符号类型,并且您在 中存储负值buff,因此当它们int在调用中转换为printf(),它们是负整数(小幅度) , 以十六进制打印。

ISO/IEC 9899:2018

实际上,链接是指向 C11 的在线草案,而不是 C18,在 HTML 中,它允许链接到标准中的相关段落。AFAIK,无论如何,这些细节在 C90、C99、C11 和 C18 之间并没有改变。

标准说普通char类型等效于signed charor 或unsigned char

§6.2.5 类型¶15

这三种类型charsigned char以及unsigned char统称为字符类型。实现应定义char为具有相同的范围,表示和行为如任一signed charunsigned char45)

45) CHAR_MIN,在 中定义<limits.h>,将具有值 0 或 之一SCHAR_MIN,这可用于区分这两个选项。无论做出char何种选择,它都是与其他两个不同的类型,并且与任何一个都不兼容。

§6.3.1.1 布尔值、字符和整数¶2,3

2 表达式中可以使用 int 或 unsigned int 的地方可以使用以下内容:

  • 具有整数类型(除了intor unsigned int的对象或表达式,其整数转换等级小于或等于intand的等级unsigned int
  • _Bool, int, signed int, 或类型的位域unsigned int

如果 anint可以表示原始类型的所有值(受宽度限制,对于位域),则将该值转换为int; 否则,它被转换为unsigned int这些称为整数促销58)所有其他类型都不受整数提升的影响。

3 整数提升保留值,包括符号。如前所述,是否将“普通”char视为有符号是实现定义的。

58)的整数优惠只应用:如通常的算术转换的一部分,某些参数表达式,以一元的操作数+-以及~运营商和所述移位运算符的两个操作数,如由它们各自的子类指定。

§6.5.2.6 函数调用¶6,7

6 如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,并将具有类型的参数float提升为double这些称为默认参数提升如果参数数量不等于参数数量,则行为未定义。如果函数定义的类型包含原型,并且原型以省略号 (, ...) 或提升后的参数类型与参数类型不兼容,行为未定义。如果函数定义的类型不包含原型,并且提升后的参数类型与提升后的参数类型不兼容,则行为未定义,但以下情况除外:

  • 一个提升类型是有符号整数类型,另一个提升类型是对应的无符号整数类型,值在两种类型中都可以表示;
  • 这两种类型都是指向字符类型或 void 的限定或非限定版本的指针。

7 如果表示被调用函数的表达式的类型确实包含原型,则参数将像通过赋值一样隐式转换为相应参数的类型,将每个参数的类型视为其非限定版本声明的类型。函数原型声明符中的省略号表示在最后一个声明的参数之后停止参数类型转换。默认参数提升是在尾随参数上执行的。

注释

注意第 6.5.2.6 节¶7 的最后两句——当char值被“整数提升”提升时,它们被提升为 a (signed) int,负值保持为负。由于 anint有 4 个字节,并且您可能拥有的所有机器都使用二进制补码算法,因此该值的最重要的 3 个字节将为每个 0xFF。

处方

到总是打印2位十六进制的字符,使用%.2X(或者%.2x如果你喜欢;也可以使用任一%02X%02x),并通过任一(unsigned char)rbuff[r_n-1]rbuff[r_n-1] & 0xFF作为参数(使用从第一示例中的变量)。或者,使用第二个示例中的变量:

printf("%.2X\n", (unsigned char)buff[i]);
printf("%.2X\n", buff[i] & 0xFF);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么打包的struct的大小是5个字节而不是4个字节?

为什么 QList 对象的大小是 4 个字节?

为什么 char* 需要 4 个字节而不是 1 个字节

为什么 sizeof(0xF) 是 4 个字节?

用wget下载的图像大小为4个字节

如何知道Node.js中字节缓冲区内容的实际大小?

struct.error:解压缩需要4个字节的缓冲区

为什么qsort恰好需要4个字节来对字符串文字进行排序?

为什么在C语言的4个字节上出现一个char字符

long的大小为8个字节,那么如何在JAVA中将其“提升”为float(4个字节)?

为什么连续写入会在缓冲区中保留4K字节?

为什么连续写入会在缓冲区中保留4K字节?

为什么gdb告诉我x86-64上的指针是4个字节?

为什么我的Short在VB.net中包含4个字节

为什么结构的底层长度会增加到4个字节?

为什么int8_t的输出格式使用4个字节?

为什么在64位平台上BSTR长度前缀为4个字节?

为什么带有 %hu% 的 printf 从堆栈中取 4 个字节而不是 2 个?

无法读取 .jpg 二进制数据,缓冲区只有 4 个字节的数据

为什么堆栈帧中局部变量数组的每个插槽都是4个字节,而不是JVM中的1个字节?

为什么在Turbo C编译器中sizeof(int)是2个字节,而在gcc Linux编译器中是4个字节?

C:将 4 个字节写入大小为 3 的区域是否会溢出目标?

我可以假设long int的大小始终为4个字节吗?

带有虚函数的类的大小增加了额外的4个字节

Java的UTF-16字符串始终使用4个字节而不是2个字节

NASM程序集,如何打印字符串数组的前4个字节

删除4个字节的UTF8字符

如何从python的s字符串中删除前4个字节

ARM程序集对字符串的解引用仅检索4个字节