简体   繁体   中英

Read an int value using a char pointer and return it

static unsigned int read24(unsigned char *ptr)
{
  unsigned int b0;
  unsigned int b1;
  unsigned int b2;
  unsigned int b3;

  b0 = *ptr++;
  b1 = *ptr++;
  b2 = *ptr++;
  b3 = *ptr;

  return ( ((b0 >> 24) & 0x000000ff) |
           ((b1 >> 8)  & 0x0000ff00) |
           ((b2 << 8)  & 0x00ff0000) |
           (b3 << 24)  & 0x00000000     // this byte is not important so make it zero
         );

} 

Here i have written a function and am trying to read 32 bits (4bytes) using a char pointer and return those 32 bits (4bytes).I have a doubt if this will work properly.Also,am i using/wasting too much memory by defining 4 different integer variables?Is there a better way to write this function. Thank you for your time.

Consider using the following approach for your task:

#include <string.h>

unsigned int read24b(unsigned char *ptr)
{
    unsigned int data = 0;
    memcpy(&data, ptr, 3);
    return data;
}

This is for case if you want direct order of bits, but I suppose you do not...

Concerning your code - you must apply mask and then make shift, eg:

unsigned int read24(unsigned char *ptr)
{
  unsigned char b0;
  unsigned char b1;
  unsigned char b2;

  b0 = *ptr++;
  b1 = *ptr++;
  b2 = *ptr;

  return ( (b0 & 0x0ff) >> 16 |
           (b1 & 0x0ff) >> 8  |
           (b2 & 0x0ff)
         );
} 

First, drop b3, since you're apparently meaning to read 24 bits you shouldn't even try to access that extra byte (what if it's not even allocated?).

Second, I think you have your shifts wrong. b0 will always be in the range [0..255], so if you >> 24, it'll become zero. There's also no need to mask anything out, since you're coming from unsigned char you know you'll only have 8 bits set. You probably want either:

return (b0 << 16) | (b1 << 8) | b2;

or

return (b2 << 16) | (b1 << 8) | b0;

depending on the endianness of your data.

As for using those intermediate ints, if you have a decent compiler it won't matter (the compiler will optimize them out). If however you're writing for an embedded platform or otherwise have a less-than state of the are compiler, it's possible that eliding the intermediate ints may help your performance. In this case, don't put multiple ptr++ s in the same statement, use ptr[n] instead to avoid undefined behavior from multiple increments.

Well, I'm not too clear on what you're attempting to do. If I'm not mistaken you want to input a char* (Most likely 4 bytes if you're running a 32 bit system) and get the same organization of bytes as an int* (4 bytes)

If all you want is the int* version of a char* set of bytes you can use type-casting:

unsigned int* result = (unsigned int*)ptr;

If you want the same collection of bytes BUT you want the most significant byte to be equal to 0 then you can do this:

unsigned int* result = (unsigned int*)ptr & 0x0FFF;

Some additional info:

- Type Casting is a method of temporarily "casting" a variable as any type you want via the use of a temporary copy that is of the type your casting the variable to You can make a variable act as any type you want if you typecast it: Example:

unsigned int varX = 48;
//Prints "Ascii decimal value 48 corresponds with: 0" 
printf ("Ascii decimal value 48 corresponds with: %c\n", (char)varX);

-Hexidicamal digits occupy one byte each. So in your code:

0x000000ff -> 8 bytes of data

0x implies that each of the place holders are a hexidecimal value and I think what you were going for was 0x000F, which would make all the other bytes 0 except the least significant byte

ANSI-C can process hexidecimal(prefix -> 0x), octal(prefix -> 0) and decimal

Hope this helped!

When building your number from the individual pointers, you must shift the numbers to the left as you incrementally Or the values together. (for little endian machines). Think of it this way, after you read b0 , that will be the least significant byte in your final number. Where do more significant bytes go? (to the left).

When you read a pointer value into b0, b1, b2, b3 , all they hold is one byte each. They have no way of knowing where they came from in the original number, so there is no "relative" shifting required. You just start with the least significant byte, and incrementally shift each successive byte to the left by 1 byte more than the last.

Below, I have used all bytes in the building of the unsigned value from the unsigned char pointers as an example. You can simply omit bytes you do not need to meet your needs.

#include <stdio.h>
#include <stdlib.h>

#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif

char *binstr (unsigned long n);
static unsigned int read24 (unsigned char *ptr);

int main (void) {

    unsigned int n = 16975631;
    unsigned int o = 0;

    o = read24 ((unsigned char *)&n);

    printf ("\n number : %u    %s\n", n, binstr (n));
    printf (" read24 : %u    %s\n\n", o, binstr (o));

    return 0;
}

static unsigned int read24 (unsigned char *ptr)
{
    unsigned char b0;
    unsigned char b1;
    unsigned char b2;
    unsigned char b3;

    b0 = *ptr++;  /* 00001111000001110000001100000001 */
    b1 = *ptr++;  /* b0      b1      b2      b3       */
    b2 = *ptr++;  /* b3      b2      b1      b0       */
    b3 = *ptr;    /* 00000001000000110000011100001111 */

    return ((b0 & 0x000000ffU)         |
           ((b1 << 8 )  & 0x0000ff00U) |
           ((b2 << 16)  & 0x00ff0000U) |
           ((b3 << 24)  & 0xff000000U));
}

/* simple return of binary string */
char *binstr (unsigned long n)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;

    if (!n) {
        *s = '0';
        return s;
    }

    while (n) {
        *(--p) = (n & 1) ? '1' : '0';
        n >>= 1;
    }
    return p;
}

Output

$ ./bin/rd_int_as_uc

 number : 16975631    1000000110000011100001111
 read24 : 16975631    1000000110000011100001111

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM