【问题标题】:how can split integers into bytes without using arithmetic in c?如何在不使用 c 算术的情况下将整数拆分为字节?
【发布时间】:2015-05-02 07:50:25
【问题描述】:

我正在用 C 实现四个基本的算术函数(加、减、除、乘)。

我想象的这些函数的基本结构是

程序通过用户使用scanf获取两个操作数,

然后程序将这些值拆分为字节并计算!

我已经完成了加减法,

但我忘了我不应该使用算术函数,

所以当将整数拆分为单个字节时,

我写了类似

的代码
    while(quotient!=0){
    bin[i]=quotient%2;
    quotient=quotient/2;
    i++;
}

但是因为有我不应该使用的算术函数..

所以我必须重写分割部分,

但我真的不知道如何在不使用的情况下将整数拆分为单个字节 % 或 /。

【问题讨论】:

  • 你的意思是分割成比特,而不是字节?
  • 我不会担心在输入到位的转换中使用算术运算符。毕竟,您正在利用scanf 中内置的更多算法来进行十进制输入到C-int 的转换。我只是考虑输入处理的这一部分,一旦有了位数组,我就担心使用或不使用算术。
  • 是的,这是我的作业.. 我不擅长它:-(

标签: c math


【解决方案1】:

要访问变量的字节,可以使用类型双关语
根据标准 C(C99 和 C11),只有unsigned char 才能确保以安全的方式执行此操作。

这可以通过以下方式完成:

typedef unsigned int myint_t;
myint_t x = 1234;
union {
  myint_t val;
  unsigned char byte[sizeof(myint_t)];
} u;

现在,你当然可以通过这种方式访问​​ x 的字节了:

u.val = x;
for (int j = 0; j < sizeof(myint_t); j++)
   printf("%d ",u.byte[j]);

但是,正如 WhozCrag 指出的那样,字节序存在问题。
不能假定字节的顺序是确定的。
因此,在使用字节进行任何计算之前,您的程序需要检查字节序是如何工作的。

#include <limits.h> /* To use UCHAR_MAX */

unsigned long int ByteFactor = 1u + UCHAR_MAX; /* 256 almost everywhere */
u.val = 0;

for (int j = sizeof(myint_t) - 1; j >= 0 ; j--)
  u.val = u.val * ByteFactor + j;

现在,当您打印 u.byte[] 的值时,您将看到为 myint_t 类型排列的字节顺序。 低位字节的值为 0。

【讨论】:

    【解决方案2】:

    我假设 32 位整数(如果不是这种情况,则只需更改大小)还有更多方法:

    1. 字节指针

      #include<stdio.h>
      int x; // your integer or whatever else data type
      BYTE *p=(BYTE*)&x;
      x=0x11223344;
      printf("%x\n",p[0]);
      printf("%x\n",p[1]);
      printf("%x\n",p[2]);
      printf("%x\n",p[3]);
      
      • 只需将数据的地址作为 BYTE 指针获取
      • 并通过一维数组直接访问字节
    2. 联合

      #include<stdio.h>
      union
       {
       int x; // your integer or whatever else data type
       BYTE p[4]; 
       } a;
      a.x=0x11223344;
      printf("%x\n",a.p[0]);
      printf("%x\n",a.p[1]);
      printf("%x\n",a.p[2]);
      printf("%x\n",a.p[3]);
      
      • 并通过一维数组直接访问字节

    [注释]

    • 如果您没有定义BYTE,则将其更改为unsigned char
    • 使用 ALU,您不仅可以使用 %,/,还可以使用 &gt;&gt;,&amp;,这速度更快,但仍可以使用算术
    • 现在,根据平台字节序,输出可以是 11,22,33,4444,33,22,11,因此您需要牢记这一点(尤其是在多个平台中使用的代码)
    • 你需要处理数字的符号,对于无符号整数没有问题
    • 但是对于有符号的 C 使用 2'os 补码,所以最好在拆分之前将符号分开:

      int s;
      if (x<0) { s=-1; x=-x; } else s=+1;
      // now split ...
      

    [edit2] 逻辑/位运算

    • x&lt;&lt;n,x&gt;&gt;n - 将 x 左右位移 n 位
    • x&amp;y - 按位逻辑和(分别对每个位执行逻辑与)
    • 因此,当您拥有例如 32 位 unsigned int(称为 DWORD)时,您可以像这样将其拆分为 BYTES:

      DWORD  x; // input 32 bit unsigned int
      BYTE a0,a1,a2,a3; // output BYTES a0 is the least significant a3 is the most significant
      x=0x11223344;
      a0=DWORD((x    )&255); // should be 0x44
      a1=DWORD((x>> 8)&255); // should be 0x33
      a2=DWORD((x>>16)&255); // should be 0x22
      a3=DWORD((x>>24)&255); // should be 0x11
      
    • 这种方法不受字节序的影响

    • 但它使用 ALU
    • 重点是移动您想要定位的0..7 位并屏蔽其余位
    • 并非所有编译器都需要 &amp;255DWORD() 过度键入,但有些编译器在没有它们的情况下会做一些奇怪的事情,尤其是在 char 或 int 等有符号变量上
    • x&gt;&gt;nx/(pow(2,n))=x/(1&lt;&lt;n) 相同
    • x&amp;((1&lt;&lt;n)-1)x%(pow(2,n))=x%(1&lt;&lt;n) 相同
    • 所以(x&gt;&gt;8)=x/256(x&amp;255)=x%256

    【讨论】:

    • 小心; union 产生的输出可以(并且在大多数情况下,将)根据运行平台的endianness 有很大差异。
    • @WhozCraig 是的,我同意,因此我将 0x11223344 写入输入,因此在输出中可以看到使用平台的顺序。但是是的,我可以在笔记中提到这一点(所以+1)。还是为什么要投反对票?而不是在不使用 ALU 的情况下提供不同的答案...?
    • 问题仅用“c”标记,而不是 c++。
    • 重新编辑了答案(将 cout 更改为 printf,并添加了一些注释)
    • 你能告诉我更多关于使用 & 和 >> 的信息吗?
    猜你喜欢
    • 2013-04-08
    • 2012-09-06
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-09
    • 2011-08-27
    相关资源
    最近更新 更多