Search code examples
c++arduinoavrarduino-c++

Zeroing-Out multiple arrays with a single memset/assuming memory layout allowed?


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?


Solution

  • 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));