CSjune
CSjune

Reputation: 23

how can split integers into bytes without using arithmetic in c?

I am implementing four basic arithmetic functions(add, sub, division, multiplication) in C.

the basic structure of these functions I imagined is

the program gets two operands by user using scanf,

and the program split these values into bytes and compute!

I've completed addition and subtraction,

but I forgot that I shouldn't use arithmetic functions,

so when splitting integer into single bytes,

I wrote codes like

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

but since there is arithmetic functions that i shouldn't use..

so i have to rewrite that splitting parts,

but i really have no idea how can i split integer into single byte without using % or /.

Upvotes: 1

Views: 944

Answers (2)

Spektre
Spektre

Reputation: 51863

I assume 32 bit integers (if not the case then just change the sizes) there are more approaches:

  1. BYTE pointer

    #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]);
    
    • just get the address of your data as BYTE pointer
    • and access the bytes directly via 1D array
  2. union

    #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]);
    
    • and access the bytes directly via 1D array

[notes]

  • if you do not have BYTE defined then change it for unsigned char
  • with ALU you can use not only %,/ but also >>,& which is way faster but still use arithmetics
  • now depending on the platform endianness the output can be 11,22,33,44 of 44,33,22,11 so you need to take that in mind (especially for code used in multiple platforms)
  • you need to handle sign of number, for unsigned integers there is no problem
  • but for signed the C uses 2'os complement so it is better to separate the sign before spliting like:

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

[edit2] logical/bit operations

  • x<<n,x>>n - is bit shift left and right of x by n bits
  • x&y - is bitwise logical and (perform logical AND on each bit separately)
  • so when you have for example 32 bit unsigned int (called DWORD) yu can split it to BYTES like this:

    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
    
  • this approach is not affected by endianness

  • but it uses ALU
  • the point is shift the bits you want to position of 0..7 bit and mask out the rest
  • the &255 and DWORD() overtyping is not needed on all compilers but some do weird stuff without them especially on signed variables like char or int
  • x>>n is the same as x/(pow(2,n))=x/(1<<n)
  • x&((1<<n)-1) is the same as x%(pow(2,n))=x%(1<<n)
  • so (x>>8)=x/256 and (x&255)=x%256

Upvotes: 0

pablo1977
pablo1977

Reputation: 4433

To access the bytes of a variable type punning can be used.
According to the Standard C (C99 and C11), only unsigned char brings certainty to perform this operation in a safe way.

This could be done in the following way:

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

Now, you can of course access to the bytes of x in this way:

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

However, as WhozCrag has pointed out, there are issues with endianness.
It cannot be assumed that the bytes are in determined order.
So, before doing any computation with bytes, your program needs to check how the endianness works.

#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;

Now, when you print the values of u.byte[], you will see the order in that bytes are arranged for the type myint_t. The less significant byte will have value 0.

Upvotes: 1

Related Questions