Symbian3/SDK/Source/GUID-8675AC01-E2D8-425C-899F-12BE99345AA9.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Fri, 11 Jun 2010 12:39:03 +0100
changeset 8 ae94777fff8f
parent 7 51a74ef9ed63
child 13 48780e181b38
permissions -rw-r--r--
Week 23 contribution of SDK documentation content. See release notes for details. Fixes bugs Bug 2714, Bug 462.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-8675AC01-E2D8-425C-899F-12BE99345AA9" xml:lang="en"><title>C++
and Machine Architecture</title><shortdesc>The C++ language, following its foundation in C, is close to the
machine architecture. This allows applications to be implemented efficiently,
but, especially for developers new to the language, presents some issues of
which you need to be aware. This topic reviews the basic language features
from this perspective, and discusses how the resulting issues are handled.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<section id="GUID-4E54823B-31A2-4FFB-997D-6FF6056F2643">       <title>Arithmetic types</title>       <p>An <codeph>int</codeph> is
usually implemented as the natural machine word size of the particular implementation.
This is 32 bits in most modern machines. It was 16 bits in older machines,
and in a few machines it may even be 64 bits.     </p><p>Similarly, a pointer
(a <codeph>void*</codeph>, for instance) is usually implemented as a machine
word but, in some machines with special architectures, a pointer may be more
complex.     </p><p>It is assumed that Symbian is implemented on a machine
with a 32-bit or greater machine word, and 32-bit pointers. The types <codeph>TInt</codeph> and <codeph>TUint</codeph> are<codeph> typedefed</codeph> onto the built-in <codeph>int</codeph> and <codeph>unsigned int</codeph> types,
and are guaranteed to be at least 32 bits.     </p><p>When you need a specific
size, regardless of implementation, use a sized type. Several of these are
available: </p><table id="GUID-8E1CEF20-AF41-4980-AA56-5CBF2B7F6A9E">
<tgroup cols="2"><colspec colname="col1"/><colspec colname="col2"/>
<tbody>
<row>
<entry><p><codeph>TInt32</codeph>, <codeph>TUint32</codeph> </p> </entry>
<entry><p>32-bit signed and unsigned integer</p>    <p> In each case, the
representation is a 32-bit machine word which, in the ARM architecture, must
be aligned to a four-byte boundary. The compiler ensures that this is always
the case.</p>  </entry>
</row>
<row>
<entry><p><codeph>TInt8</codeph>, <codeph>TUint8</codeph>, <codeph>TText8</codeph></p>  </entry>
<entry><p>8-bit signed and unsigned integer, and 8-bit character     </p><p>In
each case, the representation is an 8-bit byte, which has no specific alignment
requirements.  </p></entry>
</row>
<row>
<entry><p><codeph>TInt16</codeph>, <codeph>TUint16</codeph>, <codeph>TText16</codeph> </p></entry>
<entry><p>16-bit signed and unsigned integer, and 16-bit character     </p><p>In
each case, the representation is a 16-bit halfword, which should be aligned
to a two-byte boundary.  </p></entry>
</row>
<row>
<entry><p><codeph>TInt64</codeph>, <codeph>TUint64</codeph>  </p></entry>
<entry><p>64-bit signed and unsigned integer     </p><p>These are typedefed
to appropriate built-in types for the compiler being used (long long, and
unsigned long long for ARM RVCT).  </p></entry>
</row>
<row>
<entry><p><codeph>TReal</codeph>, <codeph>TReal64</codeph> </p></entry>
<entry><p>Double-precision floating point, IEEE754 64-bit representation 
   This is the floating-point type recommended for general use.     </p><p>You
are recommended to perform operations in integer arithmetic if possible (for
instance, most GUI calculations), and to use floating-point only when the
problem demands it (for instance, a spreadsheet application).     </p><p>On
processors that have floating point hardware, the compiler generates host
instructions which use that hardware directly. On processors which don't have
a floating point unit, the compiler implements the calculations in software.
 </p></entry>
</row>
<row>
<entry><p><codeph>TReal32</codeph> </p></entry>
<entry><p>32-bit floating point     </p><p>This is smaller and quicker, but
should only be used when space and/or time are at a true premium, as its precision
is unsatisfactory for many applications.  </p></entry>
</row>
</tbody>
</tgroup>
</table>     </section>
<section id="GUID-A89DBA31-B739-48E3-92E1-E00F50029269"><title>Compound types</title><p>Apart from classes, C++ inherits
from C various other types of compounding.     </p><p>A struct maps an area
of memory: </p><codeblock xml:space="preserve">struct TEg
    {
    TInt iInt; // offset 0, 4 bytes
    TText8 iText; // offset 4, 1 byte
        // 3 wasted bytes
    TReal iReal; // offset 8, 8 bytes
    } // total length = 16 bytes</codeblock><fig id="GUID-70477651-EC14-4321-ACA5-79CEE4AEC69E">
<image href="GUID-7E801A44-4509-5AC0-88D5-7DEA1AF7969D_d0e7090_href.png" placement="inline"/>
</fig><p>Structures are regarded as <codeph>T</codeph> types: that is they
may not own heap-allocated resources such as <codeph>C</codeph> type classes.
    </p><p>An array contains many built-ins or other types </p><codeblock xml:space="preserve">TInt a[32]; // 32 TInts, = 128 bytes  
S b[3]; // 3 Ss, = 48 bytes </codeblock><p>The main disadvantage of using
C++ arrays is that there is no automatic checking of index values. For this
reason, and to support more complex containers, C++ has evolved the Standard
Template Library (STL). Symbian does not use STL, but provides its own range
of efficient container classes, for fixed, dynamic, and associative arrays.
For details, see <xref href="GUID-2F64B579-73D3-548A-9104-16483AF77BCB.dita">Dynamic
Arrays</xref>. </p></section>
<section id="GUID-F925F040-C1A3-420A-A9A9-BDFBCDA212B2"><title>Pointers</title><p>A pointer is a memory address. If you can
take the address of an object, then you can refer to it by pointer:</p><codeblock xml:space="preserve">S* ps; // pointer to an S
ps=&amp;s // take address of existing S
</codeblock><p>A pointer is a 32-bit machine word, and could point to anything.</p><fig id="GUID-D33AB198-0B62-4391-B86D-088595AE6B8B">
<image href="GUID-045F3455-2B5A-5B20-ABCE-ED202DC5078A_d0e7121_href.png" placement="inline"/>
</fig><p>The specifier is placed next to the type rather than the name.   </p><p>There
is often a need to refer to memory as anything: for this, a <codeph>void*</codeph> pointer
is used in C++. In Symbian, a <codeph>TAny*</codeph> may be referred to instead.
A <codeph>TAny*</codeph> is a pointer to anything. </p></section>
<section id="GUID-51EBCCA6-8E19-43CC-819E-8A7F0560DE4C"><title>Strings</title><p>In C++, the basic string is an array of
characters:</p><codeblock xml:space="preserve">char* hello="hello";</codeblock><p>This statement
does two things: firstly, it sets aside six bytes of memory containing the
characters 'h', 'e', 'l', 'l', 'o', '\0'. Secondly, it sets the pointer hello
to contain the address of the first of those bytes. </p><fig id="GUID-08C1AF40-8D93-414E-B103-1E57AB17480F">
<image href="GUID-512D0DA7-0BC2-534F-9233-11F46D285CA6_d0e7148_href.png" placement="inline"/>
</fig><p>Functions accessing the string rely on this address as its starting
point, and the terminating <codeph>\0</codeph> to indicate its end. Functions
which manipulate the string must either deliberately not extend it, or must
have some cue as to the amount of memory reserved for the string (beyond the
trailing<codeph>\0</codeph>) so they know how much it can be extended. This
leads to an awkward programming style, and every C++ library provides a way
to manipulate strings more elegantly. The Symbian platform solution is <i>descriptors</i>:
these are introduced in <xref href="GUID-9C51D27D-BEDB-59D1-8F0E-8426B8FF2230.dita">Descriptors</xref></p></section>
<section id="GUID-9D9ED4A6-5C8A-4369-BCFB-0082A3A97599"><title>Functions</title><p>Functions are a piece of code which can
be called and executed from anywhere else in a program. The stack is used
to pass parameters and to contain local variables. The stack is often augmented
by machine registers, especially in a register-rich processor such as the
ARM, so that memory is often not used. But, conceptually, there is a stack,
and for the purposes of this explanation it is convenient to consider the
stack as if it were implemented entirely in memory.   </p><p>Parameters are
passed by copying or evaluating onto the called functions stack frame. It
is bad practice to pass large parameters, such as an entire struct, or, in
fact, anything beyond two machine words in size, because this involves excessive
copying. Instead, a pointer or a reference should be used to pass the address,
instead of the data itself.   </p><p>In a multi-tasking system such as Symbian,
each thread has its own stack, which is a pre-allocated area of memory. Each
function then allocates its own frame from the stack on entry, and de-allocates
it on exit. The advantage of the stack mechanism is that allocation and de-allocation
are very rapid indeed— just a couple of instructions. Also, the lifetime of
any variable on the stack is very well defined: it is the lifetime of its
owning function, or, in fact, its owning block, since functions may have blocks
within them.   </p><p>When a function returns, its stack memory is still there:
it is just not allocated. The stack memory will be re-used by the next function
that is called. A potential source of error is to allocate an object on a
functions stack frame, and then return a pointer to it: </p><codeblock xml:space="preserve">TEg* foo()
    {
    TEg s;
    TEg* ps=&amp;s
    return ps; // !! error !!
    }
</codeblock><p>This pointer will not be valid for long, because the memory
will be re-used when the next function is called. You should never allow this
to happen. This error is so obvious that a compiler will trap it. But it can
occur in more subtle forms: </p><codeblock xml:space="preserve">foo(CContainer* aContainer)
    {
    TEg s;
    TEg* ps=&amp;s
    aContainer-&gt;iMember=ps;
    }
</codeblock><p>These cannot be trapped so easily. </p></section>
<section id="GUID-19A4F40C-1177-4F71-B547-A00DE447CF55"><title>Heap</title><p>Each thread also has a heap. You can allocate
and de-allocate objects on the heap at will, and refer to them by pointer.
The benefit of a heap is that the lifetime of an object is entirely within
your control. This power comes with responsibility: you must not forget to
de-allocate objects once you have finished with them, and you must not use
pointers to objects that have been de-allocated. </p></section>
</conbody></concept>