3

Looking at the source-code of the Arduino-Ethernet-Library I found this:

class DhcpClass {
private:
...
    #ifdef __arm__
        uint8_t  _dhcpLocalIp[4] __attribute__((aligned(4)));
        uint8_t  _dhcpSubnetMask[4] __attribute__((aligned(4)));
        uint8_t  _dhcpGatewayIp[4] __attribute__((aligned(4)));
        uint8_t  _dhcpDhcpServerIp[4] __attribute__((aligned(4)));
        uint8_t  _dhcpDnsServerIp[4] __attribute__((aligned(4)));
    #else
        uint8_t  _dhcpLocalIp[4];
        uint8_t  _dhcpSubnetMask[4];
        uint8_t  _dhcpGatewayIp[4];
        uint8_t  _dhcpDhcpServerIp[4];
        uint8_t  _dhcpDnsServerIp[4];
    #endif
...

aswell as this:

void DhcpClass::reset_DHCP_lease()
{
    // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
    memset(_dhcpLocalIp, 0, 20);
}

Is this really a legal way of accessing/zeroing those arrays, which are fields of a class? Can we really safely assume that they are always in this order and always at a continuous memory location? I believe no but I don't understand why someone wouldn't just write one memset() for each array, is the performance really that much better?

J. Doe
  • 53
  • 4
  • 1
    Magic constants like this one are a bad code smell, IMHO. – 500 - Internal Server Error Oct 13 '21 at 17:12
  • https://stackoverflow.com/questions/48300491/are-members-in-a-c-class-guaranteed-be-contiguous#comment83586880_48300540 – GSerg Oct 13 '21 at 17:14
  • 1
    No, this is UB in C++. The pointer that you get that points to `_dhcpLocalIp` is only usable to point into that array, or one past then end. Any access of that past then end element or further past is UB. – NathanOliver Oct 13 '21 at 17:14
  • Does this answer your question? [Are class members guaranteed to be contiguous in memory?](https://stackoverflow.com/questions/15430848/are-class-members-guaranteed-to-be-contiguous-in-memory) – GSerg Oct 13 '21 at 17:15
  • Does this answer your question? [Are members in a c++ class guaranteed be contiguous?](https://stackoverflow.com/q/48300491/11683) – GSerg Oct 13 '21 at 17:15
  • @АлексейНеудачин What is POD? Plain old data? How does plain old data bend the [rules](https://timsong-cpp.github.io/cppwp/n4659/class.mem#17) of the memory layout of class members? – GSerg Oct 13 '21 at 17:29
  • @GSerg class declaration is not exposed here. but we can conclude it's pod . So do you understand how it deploys in memory? without links rules or wtf else? i mean in case of arm cpu so `aligned` comes into play – Алексей Неудачин Oct 13 '21 at 19:15
  • see discussion there https://stackoverflow.com/questions/68689700/why-cant-read-the-filedoesnt-display-the-data#comment121394835_68689700 – Алексей Неудачин Oct 13 '21 at 19:24
  • @АлексейНеудачин I am not particularly moved by your suggestion to ignore the C++ standard and believe you instead. I do not see how your link is relevant either. – GSerg Oct 13 '21 at 20:11

1 Answers1

1

The performance improvement is not significant, although in an arduino environment, you may be fighting to reduce every byte of generated code (more than execution speed).

As listed, the code is a bad idea, although it will "probably" work OK, that's usually not good enough.

For this case, you could do something like this:

class DhcpClass {
private:
    struct {
    #ifdef __arm__
        uint8_t  LocalIp[4] __attribute__((aligned(4)));
        uint8_t  SubnetMask[4] __attribute__((aligned(4)));
        uint8_t  GatewayIp[4] __attribute__((aligned(4)));
        uint8_t  DhcpServerIp[4] __attribute__((aligned(4)));
        uint8_t  DnsServerIp[4] __attribute__((aligned(4)));
    #else
        uint8_t  LocalIp[4];
        uint8_t  SubnetMask[4];
        uint8_t  GatewayIp[4];
        uint8_t  DhcpServerIp[4];
        uint8_t  DnsServerIp[4];
    #endif
    } _dhcp;
    void reset_DHCP_lease()
    {
        memset(&_dhcp, 0, sizeof(_dhcp));
    }
};

although you'll have to change the rest of the code to match.

Edited to add:

If the class contains no virtual methods and no other data, you could also do this:

memset(this, 0, sizeof(*this));

dirck
  • 838
  • 5
  • 10