Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer arithmetic and portability

I'm writing an application and I had to do some pointers arithmetic. However this application will be running on different architecture! I was not really sure if this would be problematic but after reading this article, I thought that I must change it.

Here was my original code that I didn't like much:

class Frame{
  /* ... */
protected:
  const u_char* const m_pLayerHeader; // Where header of this layer starts
  int m_iHeaderLength;                // Length of the header of this layer
  int m_iFrameLength;                 // Header + payloads length
};

/**
 * Get the pointer to the payload of the current layer
 * @return A pointer to the payload of the current layer
 */
const u_char* Frame::getPayload() const
{
  // FIXME : Pointer arithmetic, portability!
  return m_pLayerHeader + m_iHeaderLength;
}

Pretty bad isn't it! Adding an int value to a u_char pointer! But then I changed to this:

const u_char* Frame::getPayload() const
{
  return &m_pLayerHeader[m_iHeaderLength];
}

I think now, the compiler is able to say how much to jump! Right? Is the operation [] on array considered as pointer arithmetic? Does it fix the portability problem?

like image 422
morandg Avatar asked Dec 10 '25 13:12

morandg


2 Answers

p + i and &p[i] are synonyms when p is a pointer and i a value of integral type. So much that you can even write &i[p] and it's still valid (just as you can write i + p).

The portability issue in the example you link was coming from sizeof(int) varying across platforms. Your code is just fine, assuming m_iHeaderLength is the number of u_chars you want to skip.

like image 144
Angew is no longer proud of SO Avatar answered Dec 12 '25 04:12

Angew is no longer proud of SO


In your code you are advancing the m_pLayerHeader by m_iHeaderLength u_chars. As long as whatever wrote the data you are pointing into has the same size for u_char, and i_HeaderLength is the number of u_chars in the header area you are safe.

But if m_iHeaderLength is really referring to bytes, and not u_chars, then you may have a problem if m_iHeaderLength is supposed to advance the pointer past other types than char.

Say you are sending data from a 16-bit system to a 32-bit system, your header area is defined like this

struct Header {
    int something;
    int somethingElse;
};

Assume that is only part of the total message defined by the struct Frame.

On the 32-bit machine you write the data out to a port that the 16-bit machine will read from.

port->write(myPacket, sizeof(Frame));

On the 16-bit machine you have the same Header definition, and try to read the information.

port->read(packetBuffer, sizeof(Frame));

You are already in trouble because you've tried to read twice the amount of data the sender wrote. The size of int on the 16-bit machine doing the reading is two, and the size of the header is four. But the header size was eight on the sending machine, two ints of four bytes each.

Now you attempt to advance your pointer

m_iHeaderLength = sizeof(Header);
...
packetBuffer += m_iHeaderLength;

packetBuffer will still be pointing into the data which was in the header in the frame sent from the originator.

like image 29
Jason Avatar answered Dec 12 '25 03:12

Jason



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!