

********************
Data representation
********************

This chapter describes the available data types in detail.

.. index:: types; integer, integer types

Basic types
===========

All standard integer types are supported. The following table lists
the built-in integer types and their ranges.

.. table:: Integer types
 :widths: 2 1 4
 :column-dividers: none single single single none
 :column-alignment: left left left left

 +--------------------------+---------+------------------------------------+
 |Type name                 |Size     |Range                               |
 +==========================+=========+====================================+
 | ``bool``                 | 8 bits  |0 to 1                              |
 +--------------------------+---------+------------------------------------+
 | ``char``                 | 8 bits  |0 to 255                            |
 +--------------------------+---------+------------------------------------+
 | ``signed char``          | 8 bits  |-128 to 127                         |
 +--------------------------+---------+------------------------------------+
 | ``unsigned char``        | 8 bits  |0 to 255                            |
 +--------------------------+---------+------------------------------------+
 | ``short``                | 16 bits |-32768 to 32767                     |
 +--------------------------+---------+------------------------------------+
 | ``signed short``         | 16 bits |-32768 to 32767                     |
 +--------------------------+---------+------------------------------------+
 | ``unsigned short``       | 16 bits |0 to 65535                          |
 +--------------------------+---------+------------------------------------+
 | ``int``                  | 16 bits |-32768 to 32767                     |
 +--------------------------+---------+------------------------------------+
 | ``signed int``           | 16 bits |-32768 to 32767                     |
 +--------------------------+---------+------------------------------------+
 | ``unsigned int``         | 16 bits |0 to 65535                          |
 +--------------------------+---------+------------------------------------+
 | ``long``                 | 32 bits |:math:`-2^{31}` to :math:`2^{31}-1` |
 +--------------------------+---------+------------------------------------+
 | ``signed long``          | 32 bits |:math:`-2^{31}` to :math:`2^{31}-1` |
 +--------------------------+---------+------------------------------------+
 | ``unsigned long``        | 32 bits |0 to :math:`2^{32}-1`               |
 +--------------------------+---------+------------------------------------+
 | ``signed long long``     | 64 bits |:math:`-2^{63}` to :math:`2^{63}-1` |
 +--------------------------+---------+------------------------------------+
 | ``long long``            | 64 bits |:math:`-2^{63}` to :math:`2^{63}-1` |
 +--------------------------+---------+------------------------------------+
 | ``unsigned long long``   | 64 bits |0 to :math:`2^{64}-1`               |
 +--------------------------+---------+------------------------------------+

.. index:: types; bool, bool type

bool
----

To use the ``bool`` data type, include ``stdbool.h``, which also defines
``true`` and ``false``. The boolean data type is also available as
``_Bool`` without requiring ``stdbool.h``.

.. index:: types; character, character type

char
-----

The ``char`` type is unsigned by default. To enable signed ``char``,
compile with the ``--char-is-signed`` option. Note that the supplied C
library uses unsigned ``char``.

.. note::

   The ``char`` type differs from ``short``, ``int`` and ``long`` in
   that it defaults to being unsigned in this compiler. Standard C allows it to
   be either signed or unsigned. The rationale for making ``char``
   unsigned is that it is meant to represent a character code and in
   encoding standards like ASCII, ISO-8859-1 and Unicode, character
   values are unsigned entities.

   If you intend to use 8 bits data types in expressions, you should
   consider using ``int8_t`` or ``uint8_t`` instead. They are defined
   in  ``stdint.h``.

.. index:: types; wide character, wide character type

wchar_t
-------

The wide character type ``wchar_t`` is defined if you include
``stddef.h``.

.. index:: bit fields

Bit fields
----------

Bit fields are supported based on any integer type. A bit field value
has the same type (and signedness) as the integer base type it is
defined in and are subject to the usual conversion rules when used in
expressions.

A bit field is allocated starting from the least significant available
bitposition in its container. If there are not enough bits available
in the container to represent the bit field, a new container is
allocated.

Consider the following declaration:

.. literalinclude:: ../common/example/bitfield.c
   :language: C

The two bit fields ``a`` and ``b`` are allocated in the same 16 bits
container. Bit field ``c`` gets a 32 bits container of its
own. Finally, ``d`` and ``e`` will share the same 8 bits container while
``f`` is allocated in a separate 8 bits container as there is not room
to store it together with ``d`` and ``e``.

Bit fields should be used with care. They can be a convenient way to
pack several small values into some structure when data space is
limited. However, accessing bit fields is in general more costly in
terms of produced code, compared to using normal integer types.

.. note::

   Sometimes it can be tempting to try and map bit fields to hardware
   registers. This can work, but it makes the code more sensitive to
   using a particular compiler. It may also
   require some thinking to get it right. The alternative way of
   accessing hardware registers in its intended access width and
   manually apply shift and mask operations is often more robust.

.. index:: floating point; types, IEEE 754

Floating-point types
--------------------

Floating point values follows the IEEE 754 format and is supported in
two different sizes.

.. table:: Floating-point types
 :widths: 2 1 4
 :column-dividers: none single single single none
 :column-alignment: left left left left

 +-----------------+---------+---------------------------------------------------------------+
 |Type name        |Size     |Approximate range (normal values)                              |
 +=================+=========+===============================================================+
 | ``float``       | 32 bits |:math:`\pm1.18\times10^{-38}` to :math:`\pm3.40\times10^{38}`  |
 +-----------------+---------+---------------------------------------------------------------+
 | ``double``      | 32/64   |as ``float`` or ``long double``                                |
 +-----------------+---------+---------------------------------------------------------------+
 | ``long double`` | 64 bits |:math:`\pm2.23\times10^{-308}` to :math:`\pm1.80\times10^{308}`|
 +-----------------+---------+---------------------------------------------------------------+

Floating point numbers are represented in binary floating point
form. The size of ``double`` is 32 bits by default. This can be changed
to 64 bits by using the command-line option ``--64bit-doubles``.
The runtime library comes both in variants compiled with ``double``
set to 32 bits as well as 64 bits.

Subnormal numbers, infinity and NaN (not a number) are supported.
The ranges stated in the table are for normal floating point
numbers. Subnormal floating-point numbers extends the range of the
exponent further at the cost of gradual loss of precision in the mantissa.

Floating point exceptions and changing the rounding mode are not supported.

.. note::

   When the C256 target is enabled (using ``--target=C256``
   command-line option), the built-in hardware math module is
   used for 32-bit floating point operations. This math module does not
   support subnormal numbers; operations producing them will generate zero.

.. index:: floating point; precision, precision; floating point

32 bits format
^^^^^^^^^^^^^^

In the 32 bits format the exponent is 8 bits and the mantissa is 23
bits. The precision is between 6 and 7 decimal digits.

64 bits format
^^^^^^^^^^^^^^

In the 64 bits format the exponent is 11 bits and the mantissa is 52
bits. The precision is between 15 and 16 decimal digits.

Function pointer types
----------------------

The 65816 architecture supports 16 bits short function pointers
(``nearfunc``) and 24 bits far function pointers (``farfunc``).

.. index:: data pointer, pointer; types, index type; pointer
.. index:: pointer; index type

Data pointer types
------------------

The following data pointers are available:

.. table:: Data pointers
 :widths: 2 1 1 2
 :column-dividers: none single single single none
 :column-alignment: left left left left

 +--------------------------+---------+------------+-----------------------+
 |Name or keyword           |Size     |Index type  |Address range          |
 +==========================+=========+============+=======================+
 | Direct page  ``__tiny``  | 8 bits  |signed char |``0x00-0xff``          |
 +--------------------------+---------+------------+-----------------------+
 | Near bank ``__near``     | 16 bits |signed int  |``0x0000-0xffff``      |
 +--------------------------+---------+------------+-----------------------+
 | Far memory ``__far``     | 32 bits |signed int  |``0x000000-0xffffff``  |
 +--------------------------+---------+------------+-----------------------+
 | Far memory ``__far24``   | 24 bits |signed int  |``0x000000-0xffffff``  |
 +--------------------------+---------+------------+-----------------------+
 | Huge memory ``__huge``   | 32 bits |signed long |``0x000000-0xffffff``  |
 +--------------------------+---------+------------+-----------------------+

Each data pointer has an associated index type, always a signed integer
type. This type is used in address calculations, such as array access
with an index or advancing a pointer by adding or subtracting an
integer value.

Pointer conversions
-------------------

Function and data pointers are treated as being unsigned values. In
general, casting to a type that has fewer bits means a pointer value
gets truncated. Casting to a wider type results in zero extension.

.. index:: size_t type, type; size_t

size_t
------

This unsigned integer type holds the maximum size of an object.
On the 65816 the size of ``size_t`` is 16 bits.

.. index:: ptrdiff_t type, type; ptrdiff_t

ptrdiff_t
---------

This signed integer type represents a distance within the largest
possible object.
On the 65816 the size of ``ptrdiff_t`` is 16 bits.

Subtracting two data pointers (within the same object) yields a
``ptrdiff_t`` value, representing the number of elements between the
pointers, not the number of bytes.

.. note::

   Standard C allows referring to an element one beyond the actual
   object. Subtracting the end address from the start address may result
   in a negative result if the value exceeds the ranfe of ``ptrdiff_t``.

.. index:: type; structure, structure type, record type

Structure types
===============

Structure types are fully supported and can be nested. Structure
members are stored sequentially in the order they appear in the
declaration.

.. index:: type; union, union type

Union types
============

Union types are fully supported. The compiler also supports a useful extension that allows anonymous
unions within a structure. Consider the following code:

.. literalinclude:: ../common/example/union.c
   :language: C

The use of a declarator on the union within the structure requires an
extra step to access its members. This was relaxed in the C11 standard,
allowing you to write:

.. literalinclude:: ../common/example/union2.c
   :language: C

This C11 extension, enabled by default, allows anonymous unions to be
compiled without diagnostic messages, even though the compiler actually
supports C99.

You can enable warnings for such extensions using the ``-Wc11-extensions``
or ``-Wpedantic`` command-line options.

You can also disable such extensions with the command-line option
``--pedantic-errors``. In that case you will get an error instead.

.. index:: type; enumeration, enumeration type

Enumeration types
=================

Enumeration types are represented as ``int``. To use a smaller storage
representation, choose a smaller integral type. For a better name, use
a typedef:

.. literalinclude:: ../common/example/enum.c
   :language: C

.. index:: type qualifiers

Type qualifiers
===============

Standard C provides two type qualifiers: ``volatile`` and ``const``.

.. index:: volatile objects

Volatile objects
----------------

C has the concept of volatile objects, typically used for hardware
access. Both writing and reading volatile objects are considered
side effects that will occur.

.. index:: sequence point

Related is the concept of *sequence points* in a program. A volatile
access between two sequence points occurs between those points and
cannot be moved past a sequence point. To ensure ordered memory
accesses, make them volatile and separate them with a sequence point.
The semicolon after a statement is an example of a sequence point:

.. code-block:: C

   uint8_t volatile * mem1;
   uint8_t volatile * mem2;

   void foo () {
      *mem1 = 2;
      *mem2;
   }

In this case the write to ``mem1`` is guaranteed to be performed before
the read of ``mem2``. The read of ``mem2`` will also occur even if the
result of the read is not used.

If multiple volatile accesses are done between two sequence points the
order they happen in is undefined:

.. code-block:: C

   uint8_t volatile * mem1;
   uint8_t volatile * mem2;

   int foo () {

      return *mem1 + *mem2;
   }

In this case both ``mem1`` and ``mem2`` are read, but the order in
which they are read is undefined.

.. index:: volatile; access size

Access size
^^^^^^^^^^^

Accessing a volatile object wider than the natural register size on
the target results in access performed in several steps, as dictated by the
natural register size.

Reading and using only a portion of a scalar volatile object still
results in the entire object being read:

.. code-block:: C

   volatile uint64_t wide;

   uint16_t foo () {
      return wide;
   }

Here the volatile object is 64 bits, but we are only interested in the
lower 16 bits. In this case all 64 bits are read, the upper 48 bits
are then discarded and the function returns the lower 16 bits.

If ``wide`` was not volatile, the compiler may instead choose to only read the
lower 16 bits of the 64-bit ``wide`` variable.

Assignment results
^^^^^^^^^^^^^^^^^^

Assignments in C has an expression value. Consider:

.. code-block:: C

   volatile int var;

   int foo () {
      return var = 4;
   }

The assignment writes ``4`` to the volatile variable, but the function
return value (either ``4`` or the value read from ``var`` after
the assignment) is implementation-defined.

Avoid such constructs in your programs. Be more explicit about your
intent. To force a read after the assignment:

.. code-block:: C

   volatile int var;

   int foo () {
      var = 4;
      return var;
   }

If you want to be sure the function returns ``4``:

.. code-block:: C

   volatile int var;

   int foo () {
      var = 4;
      return 4;
   }

This clarifies the intent and ensures consistent behavior across C compilers.

.. index:: bit fields; volatile

Bit fields
^^^^^^^^^^

Accessing volatile bit fields has undefined behavior.
A bit field describes a subset of bits within its storage unit.
Adjacent bits may be accessed depending on layout.
Using volatile bit fields is discouraged.

.. note::

   Rather than using bit fields, define normal scalar values so that
   they cover hardware registers, following the defined or intended
   size of hardware register access. Then use expressions to extract
   or manipulate the part of the register you want.

.. index:: const; qualifier

Const objects
--------------

The ``const`` type qualifier indicates a read-only object. It can be
applied to data objects and pointers.

When a static object is defined as ``const``, the compiler attempts to
place it in a read-only memory section.

A pointer to a ``const`` object can point to both read-only and
writable objects. Such a pointer signifies that its user should not
attempt to alter memory. This can aid the optimizer and is considered
good practice, as it prevents unintended data alteration by parts of
the application.

.. index:: typedef, type definitions

Type definitions
================

Using type definitions (the ``typedef`` keyword) is highly
recommended, offering several benefits:

  #. Code becomes more readable with meaningful type names.
     For instance, ``speed_t`` is clearer than ``long``. Should the type
     definition change, only one location requires modification, preventing
     the need to search and selectively update ``long`` instances
     that represent speed.

  #. A ``struct fish`` can be concisely named ``fish_t``, which also hides
     its structure, if desired.

``typedef`` incurs no cost; the generated code remains identical.

.. index:: alignment

Alignment
=========

The 65816 imposes no data alignment. Data objects can start
at any address, and no padding is introduced between structure
elements.
