user88434: When I need to send multiple bytes via Wire, for example a long int, I cast it to a byte array and specify a length
long int i;
Wire.write((byte*)&i, 4);

But if I want to send bytes from more than 1 variable I need to create a buffer
byte i;
byte j;
byte message[2] = {i, j};
Wire.write(message, 2);

If I want to send them without copying the data I can put them in a struct
struct message {
  byte i;
  byte j;
};
Wire.write((byte*)&message, 2);

But this would require me to refactor existing code.
Is there any c voodoo that I can perform to send bytes of different places of my code over Wire without copying them in a buffer and without refactoring the code?

user10794: // Written by Nick Gammon
// May 2012

template <typename T> unsigned int I2C_writeAnything (const T& value)
  {
  Wire.write((byte *) &value, sizeof (value));
  return sizeof (value);
  }  // end of I2C_writeAnything

template <typename T> unsigned int I2C_readAnything(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = Wire.read();
    return i;
  }  // end of I2C_readAnything

Then in the body of your code you can:
I2C_writeAnything(message);

Similarly your other end can I2C_readAnything.
There is a small amount of refactoring required, changing the function call.

user60431: No, you cannot.
C does not guarantee any allocation properties of variables. Even if you write one variable definition right after another, both variables can have addresses assigned that have other memory in between.
So, if you want a "packet" sent via Wire that contains values of multiple variables, you need to fill a buffer with these values.
Even though C maintains the order of members of a structure, please be aware that depending on the target's architecture there can be gaps between the members for alignment. However, some compilers have language extensions to tackle this issue.

user88434: As @chrisl said, there is an internal buffer so the best I can do is just use multiple Wire.write calls, but in my case that wasn't working. I got only the last written value or rubbish data.
I dug through the source of the Wire library and found that the version in github (as of this writing) makes it possible to use multiple writes by appending to the buffer:
// set length and copy data into tx buffer
for(i = 0; i < length; ++i){
  twi_txBuffer[twi_txBufferLength+i] = data[i];
}
twi_txBufferLength += length;

But the one I have installed locally looks like this:
// set length and copy data into tx buffer
twi_txBufferLength = length;
for(i = 0; i < length; ++i){
  twi_txBuffer[i] = data[i];
}

So that explains a lot.
In case someone else also has this problem, you just need to update.
I was even too lazy to update, so I just replaced the function. Probably not the best decision, but it works!
Thanks!

user42015: No, this function overwrite of Wire.write() is meant for buffers, meaning connected spaces in memory, which can be covered by simply incrementing the buffer. That is not the case for distinct variables.
But that begs the question, why you want to do that in one call to Wire.write() in the first place. This function does not do any communication on the I2C lines, it just writes to the libraries internal buffer. The data gets actually send in Wire.endTransmission() or in the onRequest interrupts in the background (depending on where you have those write statements). Thus you already have a buffer and don't need another one. Just call Wire.write() multiple times, once for each variable. That will build up the data sequentially inside the internal buffer.

88434: <p>When I need to send multiple bytes via Wire, for example a long int, I cast it to a byte array and specify a length</p>
<pre><code>long int i;
Wire.write((byte*)&amp;i, 4);
</code></pre>
<p>But if I want to send bytes from more than 1 variable I need to create a buffer</p>
<pre><code>byte i;
byte j;
byte message[2] = {i, j};
Wire.write(message, 2);
</code></pre>
<p>If I want to send them without copying the data I can put them in a struct</p>
<pre><code>struct message {
  byte i;
  byte j;
};
Wire.write((byte*)&amp;message, 2);
</code></pre>
<p>But this would require me to refactor existing code.</p>
<p>Is there any c voodoo that I can perform to send bytes of different places of my code over Wire without copying them in a buffer and without refactoring the code?</p>
 10794: <pre><code>// Written by Nick Gammon
// May 2012

template &lt;typename T&gt; unsigned int I2C_writeAnything (const T&amp; value)
  {
  Wire.write((byte *) &amp;value, sizeof (value));
  return sizeof (value);
  }  // end of I2C_writeAnything

template &lt;typename T&gt; unsigned int I2C_readAnything(T&amp; value)
  {
    byte * p = (byte*) &amp;value;
    unsigned int i;
    for (i = 0; i &lt; sizeof value; i++)
          *p++ = Wire.read();
    return i;
  }  // end of I2C_readAnything
</code></pre>
<p>Then in the body of your code you can:</p>
<pre><code>I2C_writeAnything(message);
</code></pre>
<p>Similarly your other end can <code>I2C_readAnything</code>.</p>
<p>There is a small amount of refactoring required, changing the function call.</p>
 60431: <p>No, you cannot.</p>
<p>C does not guarantee any allocation properties of variables. Even if you write one variable definition right after another, both variables can have addresses assigned that have other memory in between.</p>
<p>So, if you want a &quot;packet&quot; sent via <code>Wire</code> that contains values of multiple variables, you need to fill a buffer with these values.</p>
<p>Even though C maintains the order of members of a structure, please be aware that depending on the target's architecture there can be gaps between the members for alignment. However, some compilers have language extensions to tackle this issue.</p>
 88434: <p>As @chrisl said, there is an internal buffer so the best I can do is just use multiple <code>Wire.write</code> calls, but in my case that wasn't working. I got only the last written value or rubbish data.</p>
<p>I dug through the source of the Wire library and found that <a href="https://github.com/arduino/ArduinoCore-avr/blob/8b327d7bede1c1245db99daeba4e168c92c11194/libraries/Wire/src/utility/twi.c#L342" rel="nofollow noreferrer">the version in github</a> (as of this writing) makes it possible to use multiple writes by appending to the buffer:</p>
<pre><code>// set length and copy data into tx buffer
for(i = 0; i &lt; length; ++i){
  twi_txBuffer[twi_txBufferLength+i] = data[i];
}
twi_txBufferLength += length;
</code></pre>
<p>But the one I have installed locally looks like this:</p>
<pre><code>// set length and copy data into tx buffer
twi_txBufferLength = length;
for(i = 0; i &lt; length; ++i){
  twi_txBuffer[i] = data[i];
}
</code></pre>
<p>So that explains a lot.</p>
<p>In case someone else also has this problem, you just need to update.</p>
<p>I was even too lazy to update, so I just replaced the function. Probably not the best decision, but it works!</p>
<p>Thanks!</p>
 42015: <p>No, this function overwrite of <code>Wire.write()</code> is meant for buffers, meaning connected spaces in memory, which can be covered by simply incrementing the buffer. That is not the case for distinct variables.</p>
<p>But that begs the question, why you want to do that in one call to <code>Wire.write()</code> in the first place. This function does <strong>not</strong> do any communication on the I2C lines, it just <strong>writes to the libraries internal buffer</strong>. The data gets actually send in <code>Wire.endTransmission()</code> or in the onRequest interrupts in the background (depending on where you have those write statements). Thus you already have a buffer and don't need another one. Just call <code>Wire.write()</code> multiple times, once for each variable. That will build up the data sequentially inside the internal buffer.</p>
