Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中的字符缓冲区中存储一个int,然后检索相同的int_C_Bit Manipulation_Bit Shift - Fatal编程技术网

在C中的字符缓冲区中存储一个int,然后检索相同的int

在C中的字符缓冲区中存储一个int,然后检索相同的int,c,bit-manipulation,bit-shift,C,Bit Manipulation,Bit Shift,我正在编写一个socket客户机-服务器应用程序,其中服务器需要向客户机发送一个大的缓冲区,并且所有缓冲区都应该单独处理,因此我想将缓冲区长度放入缓冲区中,以便客户机可以从缓冲区读取数据长度并进行相应的处理 要输入长度值,我需要将一个整数值除以一个字节,并将其存储在缓冲区中,以便通过套接字发送。我可以将整数分解为四个部分,但在合并时,我无法检索正确的值。为了演示我的问题,我编写了一个示例程序,其中我将int划分为四个char变量,然后将其合并为另一个整数。我们的目标是,加入后我应该得到同样的结果

我正在编写一个socket客户机-服务器应用程序,其中服务器需要向客户机发送一个大的缓冲区,并且所有缓冲区都应该单独处理,因此我想将缓冲区长度放入缓冲区中,以便客户机可以从缓冲区读取数据长度并进行相应的处理

要输入长度值,我需要将一个整数值除以一个字节,并将其存储在缓冲区中,以便通过套接字发送。我可以将整数分解为四个部分,但在合并时,我无法检索正确的值。为了演示我的问题,我编写了一个示例程序,其中我将int划分为四个char变量,然后将其合并为另一个整数。我们的目标是,加入后我应该得到同样的结果

这是我的小程序

#include <stdio.h>

int main ()
{
    int inVal = 0, outVal =0;
    char buf[5] = {0};

    inVal = 67502978;

    printf ("inVal: %d\n", inVal);

    buf[0] = inVal & 0xff;
    buf[1] = (inVal >> 8) & 0xff;
    buf[2] = (inVal >> 16) & 0xff;
    buf[3] = (inVal >> 24) & 0xff;

    outVal = buf[3];
    outVal = outVal << 8;
    outVal |= buf[2];
    outVal = outVal << 8;
    outVal |= buf[1];
    outVal = outVal << 8;
    outVal |= buf[0];

    printf ("outVal: %d\n",outVal);
    return 0;
}
#包括
int main()
{
int inVal=0,outVal=0;
char buf[5]={0};
无效=67502978;
printf(“无效:%d\n”,无效);
buf[0]=无效&0xff;
buf[1]=(无效>>8)&0xff;
buf[2]=(无效>>16)&0xff;
buf[3]=(无效>>24)&0xff;
outVal=buf[3];

outVal=outVal对
inVal
outVal
使用
unsigned char buf[5]={0};
unsigned int
,它应该可以工作

使用有符号整数类型时,会出现两类问题:

首先,如果
buf[3]
为负,则由于
outVal=buf[3]
变量
outVal
变为负;随后
outVal
上的位移位运算符为未定义行为:


对于有符号和正a,a的值一个问题是对有符号的数字使用位运算符。这总是一个坏主意,几乎总是不正确。请注意,
char
具有实现定义的有符号性,而
int
总是有符号的

因此,您应该将
int
替换为
uint32\u t
,将
char
替换为
uint8\u t
。使用这种无符号类型,您可以消除在负数上使用位移位的可能性,这将是一个错误。同样,如果将数据移位到有符号数的符号位,您将得到错误


不用说,如果整数不是4字节大,则代码将不起作用。

C++标准N3936引用了移位运算符:


E1的值由于架构之间的endian差异,最佳做法是将数值转换为
网络顺序
,即大端。收到后,可以将其转换为本机主机顺序。我们可以通过使用
htonl()
(主机到网络“long”=uint32\t)以可移植的方式进行此操作,并在收到时使用
ntohl()
转换为主机订单。示例:

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char **argv) {
  uint32_t inval = 67502978, outval, backinval;

  outval = htonl(inval);
  printf("outval: %d\n", outval);
  backinval = ntohl(outval);
  printf("backinval: %d\n", backinval);
  return 0;
}

虽然有符号值的位移位可能是个问题,但这里的情况并非如此(所有左侧值均为正值,所有结果均在32位无符号整数的范围内)

语义有些不直观的问题表达式是最后一个按位OR:

outVal |= buf[0];
buf[0]
是一个(在您和我的体系结构上)值为-126的有符号字符,原因很简单,因为67502978的最低有效字节中的最高有效位已设置。在C中,算术表达式中的所有操作数都要进行算术转换。具体来说,它们进行整数提升,即:“如果整数可以表示原始类型[…]的所有值,则该值将转换为整数”。相应地,有符号字符
buf[0]
将转换为(有符号的)
int
,保留其值-126。负有符号int设置了符号位。使用另一个有符号int对其进行排序也会设置结果的符号位,使该值为负。这正是我们所看到的


使字节
无符号字符
s修复此问题,因为无符号字符转换为的临时整数的值是一个简单的8位值130。

您的方法具有潜在的实现定义行为和未定义行为:

  • 将值存储到类型
    char
    的数组中,超出类型
    char
    的范围,具有实现定义的行为:
    buf[0]=inVal&0xff;
    和接下来的3条语句(
    inVal&0xff
    如果
    char
    类型默认签名,则可能大于
    char\u MAX

  • 左移负值调用未定义的行为:如果数组中前3个字节中的任何一个变为负值,作为将大于
    CHAR_MAX
    的值存储到数组中的实现定义结果,结果
    outVal
    变为负值,则左移未定义

在您的特定示例中,您的体系结构对负值使用2的补码表示,并且类型
char
是有符号的。存储在
buf[0]
中的值是
67502978&0xff=130
,成为
-126
。最后一条语句
outVal |=buf[0];
设置
outVal
的第7位到第31位,结果是
-126

您可以通过使用
无符号字符
数组和
无符号int
类型的值来避免这些问题:

#include <stdio.h>

int main(void) {
    unsigned int inVal = 0, outVal = 0;
    unsigned char buf[4] = { 0 };

    inVal = 67502978;

    printf("inVal: %u\n", inVal);

    buf[0] = inVal & 0xff;
    buf[1] = (inVal >> 8) & 0xff;
    buf[2] = (inVal >> 16) & 0xff;
    buf[3] = (inVal >> 24) & 0xff;

    outVal = buf[3];
    outVal <<= 8;
    outVal |= buf[2];
    outVal <<= 8;
    outVal |= buf[1];
    outVal <<= 8;
    outVal |= buf[0];

    printf("outVal: %u\n", outVal);
    return 0;
}
#包括
内部主(空){
无符号int-inVal=0,outVal=0;
无符号字符buf[4]={0};
无效=67502978;
printf(“无效:%u\n”,无效);
buf[0]=无效&0xff;
buf[1]=(无效>>8)&0xff;
buf[2]=(无效>>16)&0xff;
buf[3]=(无效>>24)&0xff;
outVal=buf[3];

outVal这可能是一个糟糕的主意,但出于兴趣,我会将其张贴在这里-您可以使用:


您的体系结构是否可能具有64位
int
s?您在何处看到溢出整数操作?所有移位都在(afaics none overflow)
int
s上完成。这不是整数溢出,而是符号的直接操作
#include <stdio.h>

int main(void) {
    unsigned int inVal = 0, outVal = 0;
    unsigned char buf[4] = { 0 };

    inVal = 67502978;

    printf("inVal: %u\n", inVal);

    buf[0] = inVal & 0xff;
    buf[1] = (inVal >> 8) & 0xff;
    buf[2] = (inVal >> 16) & 0xff;
    buf[3] = (inVal >> 24) & 0xff;

    outVal = buf[3];
    outVal <<= 8;
    outVal |= buf[2];
    outVal <<= 8;
    outVal |= buf[1];
    outVal <<= 8;
    outVal |= buf[0];

    printf("outVal: %u\n", outVal);
    return 0;
}
union my_data
{
    uint32_t one_int;

    struct
    {
        uint8_t  byte3;
        uint8_t  byte2;
        uint8_t  byte1;
        uint8_t  byte0;
    }bytes;
};


// Your original code modified to use union my_data
#include <stdio.h>

int main(void) {
    union my_data data;
    uint32_t inVal = 0, outVal = 0;
    uint8_t buf[4] = {0};

    inVal = 67502978;

    printf("inVal: %u\n", inVal);

    data.one_int = inVal;

    // Populate bytes into buff    
    buf[3] = data.bytes.byte3;
    buf[2] = data.bytes.byte2;
    buf[1] = data.bytes.byte1;
    buf[0] = data.bytes.byte0;

    return 0;
}
union my_data
{
    uint32_t one_int;
    uint8_t  bytes[4];
};