0

I read some codes below:

typedef unsigned int uint32_t;    
typedef unsigned short uint16_t;

inline uint16_t NS(uint16_t i16)
{
    return((i16 << 8) | (i16 >> 8));
}

inline uint32_t NL(uint32_t i32)
{
    return((uint32_t(NS(i32)) << 16) | NS(i32>>16));
}

char* data = (char*) malloc(10);

strcpy(data, "123456789");
const char *m_data = (const char *)data;
uint32_t i32 = *((uint32_t*)m_data);
i32 = NL(i32);
m_data += 4u;

I don't understand uint32_t i32 = *((uint32_t*)m_data);,what does it mean?

And don't understand i32 = NL(i32); m_data += 4u; and the function NS and NL.

can someone tell me?

heida
  • 3
  • 2

3 Answers3

1

The code is buggy (it leaks memory):

char* data = (char*) malloc(10);
data="123456789\0";

should be:

char* data = (char*) malloc(10);
strcpy(data, "123456789");

It also means that you can't tell anything about the alignment of the pointer in data, whereas the assignment from malloc() guarantees the data is sufficiently well aligned for any basic type. However, that's partly tangential to the issue of the next two lines:

const char *m_data = (const char *)data;
uint32_t i32 = *((uint32_t*)m_data);

The cast in the first of those lines is unnecessary, but does no harm. The next line treats the pointer stored in m_data as a uint32_t pointer, dereferences it, and assigns the result to i32. If the value in m_data came from data which came from malloc(), the data would be sufficiently well aligned for this not to be a problem. With the string assignment, there is no guarantee that the pointer in m_data is well enough aligned to be used as a uint32_t pointer. So all hell might break loose, or you might be fine. The behaviour is undefined because of the memory leak.

The NS() function byte-swaps a 16-bit integer. The NL() function swaps 16-bit values within a 32-bit integer. That means you start with the value shown in the 'Start' diagram and end up with the value shown in the 'Finish' diagram.

+------+------+------+------+
|  MSB | NMSB | NLSB |  LSB |   Start
+------+------+------+------+

+------+------+------+------+
|  LSB | NLSB | NMSB |  MSB |   Finish
+------+------+------+------+

The m_data += 4u; adds 4 to the pointer m_data, so instead of pointing at the 1 of the string, it points at the 5.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • The [casting of the return value of `malloc()`](http://stackoverflow.com/q/605845/2173917) can be removed. – Sourav Ghosh Jan 06 '15 at 05:39
  • uint32_t i32 = *((uint32_t*)m_data); what is the result? – heida Jan 06 '15 at 05:47
  • It depends on the platform — you get different results on Intel compared with say SPARC or Power (little-endian vs big-endian). On big-endian, you get 0x31323334; on little-endian, you get 0x34333231. What did you get when you ran it? Or did it crash? – Jonathan Leffler Jan 06 '15 at 05:49
  • get 0x34333231.But I don't understand why to cast.Actually,the datas were from network. – heida Jan 06 '15 at 06:38
  • You cast because if you write `uint32_t i32 = *m_data;` you only get the value from the single byte that `m_data` points at (because it is a `const char *`), so the value without the cast would be 0x31. – Jonathan Leffler Jan 06 '15 at 06:44
0
uint32_t i32 = *((uint32_t*)m_data);

This literally means to take interpret the pointer m_data as a pointer to uint32_t and dereference it. The intent is to interpret the characters specified by data as a uint32_t.

The functions NS and NL appear to be taking the bitwise OR of the left and right halves of their parameters and returning it.

m_data += 4u;

This should be equivalent to the same statement without the unsigned suffix. It just increments the pointer m_data to point at the character at the address four characters above where it was pointing before.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
0

When NS is given a 16-bit value i16 thus (each character being one bit):

aaaaaaaabbbbbbbb

then the expression i16 << 8 (bit-shift left by 8 bits, feeding in zero-bits on the right) will give you bbbbbbbb00000000 and i16 >> 8 will give 00000000aaaaaaaa. ORing those together gives:

   bbbbbbbb00000000
OR 00000000aaaaaaaa
   ----------------
   bbbbbbbbaaaaaaaa

In other words, it's swapping the two bytes.

Ditto for the N32 function swapping 16-bit halves within a 32-bit value but, because it also calls N16 on each of those halves, it performs the following conversion:

aaaaaaaabbbbbbbbccccccccdddddddd
               ||
               VV
ddddddddccccccccbbbbbbbbaaaaaaaa

This is commonly used when converting to or from network-byte order when the ordering is different on your particular architecture.


The statement series:

const char *m_data = somethingOrOther;
uint32_t i32 = *((uint32_t*)m_data);

works as follows. First it converts the character pointer to a 32-bit-value pointer. Then, it dereferences that pointer to extract the 32-bit value.

What this means is that the first four characters of the string (assuming char data type is eight bits) of "1234" will be treated as a 32-bit integer value, and passed to N32 to undergo the above-mentioned byte-swapping stuff.

And, finally, the m_data += 4u simply adds the unsigned value 4 to the character pointer so that it advances to the next 32-bit value (at "5678").

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953