user41638: This sounds straightforward enough, but I'm struggling to find a good answer.
Suppose I declare a C++ class with private members that collectively occupy an odd number of bytes. Say...
class Foo {
private:
    uint8_t bitflags;
    uint32_t millis;
}

or
class Foo {
private:
    uint8_t rawData[3];
}

If I compile it using GCC or Clang (possibly, wrapped inside the Arduino IDE, or multiply-wrapped inside PlatformIO, CMake, and an IDE like CLion), is there any likely scenario where the compiler (when targeting 8-bit AVR... specifically, the ATmega2560 on an Arduino Mega2560) would be inclined to add padding bytes to the portion of the class stored in SRAM? Say... between bitflags and millis, or between an instance of Foo and a uint64_t right after it?
If yes, what do I need to use to tell the compiler, "absolutely, positively DO NOT pad variables in SRAM (and, if you find yourself in a situation where it's seemingly unavoidable, at least output a prominent compile-time warning, if not an outright compilation-stopping error)?
Then... if I do that... are there any negative consequences to doing that with code that's targeting (and ultimately running upon) an 8-bit AVR?
As far as I know, 8-bit AVR has never had specific opcodes for copying a pair of consecutive bytes between registers and SRAM (I think, because Atmel literally ran out of opcode mapping space, and had nowhere to put hypothetical new opcodes like, "ldw rz, $f00d"), and movw only applied to pairs of registers... so, in theory, there's no reason for the compiler to "optimize" SRAM access to be word-aligned.
That said... I suppose it's not inconceivable that a compiler might default to word-alignment (even on platforms where it doesn't matter), just for the sake of ABI consistency between different platforms.
Before someone suggests, "try it and see!"... I've gotten far enough into learning C++ to know that with C++, you can't trust "compiles without errors and passes unit tests on my computer, with {this} IDE" as a general-purpose proof-of-correctness for C++ involving "implementation-defined" or "undefined" behavior. AFAIK, padding behavior is "implementation-defined".

user60431: GCC has an extension to add attributes to types, which you can use to tell it your alignment requirements.
Additionally it has a #pragma to define the alignment, which could be used alternatively.
But as you already suspect, for this 8-bit target there should be no reason to insert padding bytes.

So your question boils down to find a method to detect unwanted padding. You can do this in a standard compliant way, which I show below. Yes, it does introduce additional types, one per structure. But it does not generate any unnecessary objects that eat your precious resources.
The "trick" is to use the sizeof operator to calculate a valid array size only, if the size of the checked type meets the expectation. If not, a compiler error safely breaks the generation of code. Granted, the error message is misleading an unsuspecting user, so it is really necessary to name the macro and the type accordingly.
This example compiles successfully with a PC as target, but not with an AVR as target. This is intentionally to demonstrate the working, because with an AVR target the type UP should have no padding bytes.
#define ASSERT_TYPE_SIZE(Type, size) \
    typedef char Assert##Type##Size[2 * (sizeof(Type) == (size)) - 1]

typedef struct {
    char c;
    long l;
} UP;
ASSERT_TYPE_SIZE(UP, sizeof (long) + sizeof(long));

typedef struct __attribute__((packed)) {
    char c;
    long l;
} P1;
ASSERT_TYPE_SIZE(P1, sizeof (char) + sizeof(long));

#pragma pack(1)
typedef struct {
    char c;
    long l;
} P2;
ASSERT_TYPE_SIZE(P2, sizeof (char) + sizeof(long));
#pragma pack()


41638: <p>This sounds straightforward enough, but I'm struggling to find a good answer.</p>
<p>Suppose I declare a C++ class with private members that collectively occupy an odd number of bytes. Say...</p>
<pre><code>class Foo {
private:
    uint8_t bitflags;
    uint32_t millis;
}
</code></pre>
<p>or</p>
<pre><code>class Foo {
private:
    uint8_t rawData[3];
}
</code></pre>
<p>If I compile it using GCC or Clang (possibly, wrapped inside the Arduino IDE, or multiply-wrapped inside PlatformIO, CMake, and an IDE like CLion), is there any likely scenario where the compiler (when targeting 8-bit AVR... specifically, the ATmega2560 on an Arduino Mega2560) would be inclined to add padding bytes to the portion of the class stored in SRAM? Say... between <code>bitflags</code> and <code>millis</code>, or between an instance of <code>Foo</code> and a <code>uint64_t</code> right after it?</p>
<p>If yes, what do I need to use to tell the compiler, &quot;absolutely, positively <em><strong>DO NOT</strong></em> pad variables in SRAM (and, if you find yourself in a situation where it's seemingly unavoidable, at least output a prominent compile-time warning, if not an outright compilation-stopping error)?</p>
<p>Then... if I do that... are there any negative <em>consequences</em> to doing that with code that's targeting (and ultimately running upon) an 8-bit AVR?</p>
<p>As far as I know, 8-bit AVR has <em>never</em> had specific opcodes for copying a <em>pair</em> of consecutive bytes between registers and SRAM (I think, because Atmel literally ran out of opcode mapping space, and had nowhere to <em>put</em> hypothetical new opcodes like, &quot;ldw rz, $f00d&quot;), and <code>movw</code> only applied to pairs of <em>registers</em>... so, in theory, there's no reason <em>for</em> the compiler to &quot;optimize&quot; SRAM access to be word-aligned.</p>
<p>That said... I suppose it's not inconceivable that a compiler might <em>default</em> to word-alignment (even on platforms where it doesn't <em>matter</em>), just for the sake of ABI consistency between different platforms.</p>
<p>Before someone suggests, &quot;try it and see!&quot;... I've gotten far enough into learning C++ to know that with C++, you <em><strong>can't trust</strong></em> &quot;compiles without errors and passes unit tests on <em>my computer</em>, with <em>{this} IDE</em>&quot; as a general-purpose proof-of-correctness for C++ involving &quot;implementation-defined&quot; or &quot;undefined&quot; behavior. AFAIK, padding behavior is &quot;implementation-defined&quot;.</p>
 60431: <p>GCC has an extension to add attributes to types, which you can use to tell it your alignment requirements.</p>
<p>Additionally it has a <code>#pragma</code> to define the alignment, which could be used alternatively.</p>
<p>But as you already suspect, for this 8-bit target there should be no reason to insert padding bytes.</p>
<hr />
<p>So your question boils down to find a method to detect unwanted padding. You can do this in a standard compliant way, which I show below. Yes, it does introduce additional types, one per structure. But it does not generate any unnecessary objects that eat your precious resources.</p>
<p>The &quot;trick&quot; is to use the <code>sizeof</code> operator to calculate a valid array size only, if the size of the checked type meets the expectation. If not, a compiler error safely breaks the generation of code. Granted, the error message is misleading an unsuspecting user, so it is really necessary to name the macro and the type accordingly.</p>
<p>This example compiles successfully with a PC as target, but not with an AVR as target. This is intentionally to demonstrate the working, because with an AVR target the type <code>UP</code> should have no padding bytes.</p>
<pre class="lang-c prettyprint-override"><code>#define ASSERT_TYPE_SIZE(Type, size) \
    typedef char Assert##Type##Size[2 * (sizeof(Type) == (size)) - 1]

typedef struct {
    char c;
    long l;
} UP;
ASSERT_TYPE_SIZE(UP, sizeof (long) + sizeof(long));

typedef struct __attribute__((packed)) {
    char c;
    long l;
} P1;
ASSERT_TYPE_SIZE(P1, sizeof (char) + sizeof(long));

#pragma pack(1)
typedef struct {
    char c;
    long l;
} P2;
ASSERT_TYPE_SIZE(P2, sizeof (char) + sizeof(long));
#pragma pack()
</code></pre>
