<!--order=2-->


<h1>Memory and Data Types</h1>
<p>Low-level programming gets easier when you can move confidently between the values you see in source code, the bytes stored in memory, and the widths used by the processor. This guide builds that vocabulary before the companion article on signed and unsigned values.</p>

<h2>Bits, Bytes, and Binary</h2>
<p>A bit stores either <code>0</code> or <code>1</code>. Each position to the left is worth twice the position before it:</p>
<pre>
Binary:  00  01  10  11
Decimal:  0   1   2   3
</pre>
<p>The rightmost position is the least significant bit (LSB). The leftmost position is the most significant bit (MSB) in the width being discussed.</p>
<p>Eight bits make one byte. The positions in an eight-bit byte are:</p>
<pre>
128 64 32 16 8 4 2 1
</pre>
<p>So <code>11111111</code> is <code>255</code> in decimal. An unsigned byte can represent <code>0</code> through <code>255</code>.</p>

<h2>Hexadecimal</h2>
<p>Hexadecimal is base 16. It uses <code>0</code> through <code>9</code>, followed by <code>A</code> through <code>F</code> for the values 10 through 15. One hex digit represents four bits, so two hex digits represent one byte:</p>
<pre>
Binary:      0011 1110
Hexadecimal: 3    E
Decimal:     62
</pre>
<p>Portable C11 uses <code>0x</code> for hexadecimal literals, so write <code>0x3e</code> when the base needs to be obvious. C23 adds the <code>0b</code> binary-literal prefix, and many compilers or assemblers accept it as an extension, but it is not standard C11 syntax. A bare value such as <code>3e</code> is not a valid C integer literal.</p>

<h2>Storage Widths</h2>
<p>These names describe common widths. A halfword is 16 bits (two bytes), not four bytes:</p>
<table>
  <thead><tr><th>Name</th><th>Bits</th><th>Hex digits</th><th>Unsigned maximum</th></tr></thead>
  <tbody>
    <tr><td>Byte</td><td>8</td><td>2</td><td>255</td></tr>
    <tr><td>Halfword</td><td>16</td><td>4</td><td>65,535</td></tr>
    <tr><td>Word</td><td>32</td><td>8</td><td>4,294,967,295</td></tr>
    <tr><td>Doubleword</td><td>64</td><td>16</td><td>18,446,744,073,709,551,615</td></tr>
  </tbody>
</table>
<p>Leading zeroes show a chosen width without changing the value:</p>
<pre>
0x3e                 // 8-bit display
0x003e               // 16-bit display
0x0000003e           // 32-bit display
0x000000000000003e   // 64-bit display
</pre>
<p>All four values above are decimal <code>62</code>. The surrounding context determines whether the width matters.</p>

<h2>C Integer Types</h2>
<p>When a C program needs a specific width, use the fixed-width types from <code>&lt;stdint.h&gt;</code> instead of assuming that plain <code>int</code> or <code>long</code> has the same size everywhere:</p>
<pre>
#include &lt;stdint.h&gt;

uint8_t  byte_value;
uint16_t halfword_value;
uint32_t word_value;
uint64_t doubleword_value;

int32_t  signed_word;
int64_t  signed_doubleword;
</pre>
<p>Use <code>sizeof</code> to inspect the size of a type on the target system:</p>
<pre>
printf("%zu\n", sizeof(uint32_t));  // normally 4
printf("%zu\n", sizeof(uint64_t));  // normally 8
</pre>
<p>The fixed-width types are useful when a value is part of a file format, network packet, device register, or assembly interface. They do not remove the need to think about byte order when bytes cross a machine boundary.</p>

<h2>Memory Is Addressed in Bytes</h2>
<p>Most modern systems address memory one byte at a time. A multi-byte value therefore occupies consecutive addresses, and the machine's byte order determines which byte appears first in memory. Little-endian systems store the least significant byte first; big-endian systems store the most significant byte first.</p>
<p>Do not infer a value's type from a byte dump alone. The same bytes can be an integer, a character sequence, an instruction, or part of a larger structure depending on the program that interprets them.</p>

<h2>Connection to AArch64</h2>
<p>AArch64 general-purpose registers can be accessed as a full 64-bit <code>xN</code> register or as the lower 32-bit <code>wN</code> view. The companion <a href="categories.php?cat=Code&amp;article=Data%20Types%20Part%202%20-%20Signed%20and%20Unsigned%20Values">Data Types Part 2</a> article explains how signedness and those register views affect interpretation.</p>

<h2>Takeaways</h2>
<ul>
  <li>A bit is one binary digit; eight bits make a byte.</li>
  <li>One hexadecimal digit represents four bits.</li>
  <li>A halfword is 16 bits, a word is 32 bits, and a doubleword is 64 bits.</li>
  <li>Use fixed-width C types when the representation must be predictable.</li>
  <li>A byte dump has no meaning without its width, byte order, and intended type.</li>
</ul>

<h2>References</h2>
<ul>
  <li><a href="https://en.cppreference.com/w/c/types/integer.html" target="_blank" rel="noopener">C fixed-width integer types ↗</a></li>
  <li><a href="https://learn.sparkfun.com/tutorials/binary/bits-nibbles-and-bytes" target="_blank" rel="noopener">SparkFun — Bits, Nibbles, and Bytes ↗</a></li>
  <li><a href="https://developer.arm.com/documentation/102374/latest" target="_blank" rel="noopener">Arm A64 Instruction Set Architecture Guide ↗</a></li>
</ul>