1. Why variants are necessary
Software for embedded systems should be run under different conditions:
-
very fast realtime
-
small memory available
-
C or C++ usage
-
elaborately error checks
-
test conditions
-
safety or fast
The user software itself should not be changed for this challenges, that is the concept of emC: embedded multiplatform C/C++
2. applstdef_emC.h to control the variants
The variants can be controlled by the content of a central <applstdef_emC.h> file. This file contains some settings, may be application specific, but some settings are used for the emC sources immediately. They are presented in the next chapters.
Additionally some defines can be applied as call arguments of the compiler. This is used for the emc_Test because the make scripts are written as Zmake scripts, version controlled and obviously visible what is happen. For the Test_emC is seems to be proper because a lot of variants should be especially tested. But usually the defines on the compile line are not obviously visible in version manangement because compiler control files are often complex (they are the settings of the project in an IDE).
Implementations of the same sources on different platforms may need different variants, it means different <applstdef_emC.h> each per platform and build configuration. This maybe true also on similar PC simulation, and implementation on the same platform with different approaches, maybe for the released version and a test version with the target platform. The different necessary <applstdef_emC.h> should be stored on different paths which are select by the include path for the different build configurations.
The emC basic headers regard the variants of compiling conditions. The user software can call operations, which may be macros specified to the variants. The user software should not regard the variants.
One of the basic idea of emC is: Test in a PC-based high level C++ compilation environment - and deploy the well tested software on target under the target conditions. All sophisticated software checks are done on PC testing, the software should be widely error-free after them and can deploy without these checks on target to run fastly - without adapting the sources. It means the software can be run and checked again on PC for enhancements, without change the sources, and without sophisticated #ifdef constructs.
In conclusion the target compilation and the PC test compilation can or should use different variants, for example on PC with exception handling in C++ which may not available on target.
3. Content of applstdef_emC
This file contains some compiler switch definitions and an implementation specifically selection of general header files to support a platform unspecific programming of the user’s application using the emC approach.
This file is not necessary for driver and unspecific platform adaptions, elsewhere this files uses the emC exception handling. For exception handling it is necessary to decide through the applstdef_emC.h
which approach is used.
If the applstdef_emC.h
is included in common emC library sources. Hence this compilation units should be compiled application specific. It is not usefull to store it in an unspecific library. Because: The behavior is even controlled by the application specific applstdef_emC.h
. Hence a pre-compiled library concept is not adequate for the emC concept. Libraries can be used to leave it up to the linker to select the necessary objects for a build. But the libraries should be build specific for the application with the given associated applstdef_emC.h
.
The applstdef_emC.h
can be adapted to the requirements of the application, other than compl_adaptio.h
which should be application independent but platform dependent. The applstdef_emC.h
can be different for several targets where the platform should be running. For example - with exception handling on test of the algorithm on PC, without exception handling for a poor target.
It means, for 4 applications and 3 targets, only 3 versions of compl_adaption.h
are necessary, but maybe 12 versions of applstdef_emC.h
. The differentiation is done by the include path (for the platforms) and the association of applstdef_emC.h
to the application specific files.
4. Selection of Granulatity of the ObjectJc base class
The ObjectJc
base class can be used for struct
or class
definitions to check the instance’s type and to get reflection information. ObjectJc
can be elaborately used for test platforms because it can refer all symbolic information about the struct’s elements. But for an implementation in a simple 'poor' platform it can be reduced at least to only one int32
value. Of course symbolic information cannot be gotten then, and the type test is reduced to only a number for comparison. But if the platform is 'poor' (less memory) it shouln’t be necessary. The important fact is, that a reused library source can be used without change for more or lesser capability of all ObjectJc
base data.
In the applstdef_emC.h
there is decide about the features of ObjectJc
/**Define the granularity of the ObjectJc base class: */ #define DEF_NO_ObjectJc_emC //#define DEF_ObjectSimple_emC //#define DEF_ObjectJc_SYNCHANDLE //#define DEF_ObjectJcpp_REFLECTION //#define DEF_ObjectJc_OWNADDRESS //#define DEF_ObjectJc_LARGESIZE /**Define of the offering of Reflection information: */ #define DEF_REFLECTION_NO //#define DEF_REFLECTION_SIMPLE //#define DEF_REFLECTION_OFFS //#define DEF_REFLECTION_FULL
Some defines should be activated, some are commented.
DEF_NO_ObjectJc_emC
This is for startup and for really poor controllers. No further include is necessary.
The content of ObjectJc
is reduced to one simple int
variable
which can be used as identification number.
Using ObjectSimple_emC.h:
-
DEF_ObjectSimple_emC
decides that in#include <emC/Base/Object_emC.h>
only the file<emC/Base/ObjectSimple_emC.h>
is included, and not the more complex<emC/Base/ObjectRefl_emC.h>
. It means that the users project should not know a lot of files from the emC source pool. See ObjectJc_en.html#ObjectSimple -
If
DEF_ObjectSimple_emC
is not set, the<emC/Base/ObjectRefl_emC.h>
is included which declares more capability which are implemented in some more files. -
DEF_ObjectSimple_emC
andDEF_REFLECTION_NO
decide that anObjectJc
in<emC/Base/ObjectSimple_emC.h>
is minimalistic. It contains only anint32
value, see ObjectJc_en.html#ObjectSimple. This variant should be used if very less RAM is available on the target, but the full ObjectJc capability should be used on another target or for PC test.ObjectJc
is used as base class, for some data, but it does not need significant RAM space. With this setting the application can check the instance type, but only with a number, and size of the data object. A base type cannot be detected. If it is necessary, then other thanDEF_REFLECTION_NO
should be used. -
DEF_ObjectSimple_emC
set with eitherDEF_REFLECTION_SIMPLE
orDEF_REFLECTION_OFFS
decide that anObjectJc
has a reference to a simpleClassJc
instance. IfDEF_REFLECTION_SIMPLE
is given, only a simple type test is possible, but with base type check. IfDEF_REFLECTION_OFFS
is given, using the InspcTargetProxy concept an access to all full symbolic information is possible. In both cases a base type with single inheritance can be checked. Hence it is possible to check whether a given instance with an unknown type is proper for an algorithm, which uses the base data. Then astatic_cast<MyBaseType>
on class usage or a simple C cast from theObjectJc*
reference can be done. The type may be necessary to check in an application before cast. It is an replacement for RunTimeTypeInformation. Activating this switch needs additionally 4 bytes forObjectJc
in 32-bit-systems. -
If
DEF_ObjectSimple_emC
is given, the otherDEF_ObjectJc_…
definitions are not effective.
Using ObjectRefl_emC.h
-
If
DEF_ObjectSimple_emC
is not given,<emC/Base/ObjectRefl_emC.h>
will be included with more possibilities. -
DEF_ObjectJcpp_REFLECTION
decides that theObjectJc
data contains an offset from instance address to theObjectJc
data. This is necessary for C++ usage of reflection information, if the C++classes
uses virtual tables multi inheritance. Then theObjectJc
is not on position 0 of the class. The offsets of fields in the reflection information are related to theObjectJc
. Elsewhere it is not possible to address the fields correctly if an instance is referenced by a base type pointer. This base type pointer can refer another address as the instance address, even the address of the base data inside the instance. It should be possible to getObjectJc
from any base type, and nevertherless to get all instance data, though only the base type is known. This#define
is only then not necessary for C++ usage if virtual operations and multi inheritance are not used onObjectJc
-containing types using reflection access. If it is combined withDEF_ObjectSimple_emC
then an instance identifier cannot be stored, because this bits are necessary. -
DEF_ObjectJc_SYNCHANDLE
decides that adequate routines for ObjectJc for locking and notify can used as in Java. -
DEF_ObjectJc_OWNADDRESS
decides that the own address of the instance is stored theObjectJc
data. This may be necessary if the data are stored as image and some references are existent between this image-stored data. -
DEF_ObjectJc_LARGESIZE
: TheObjectJc
has always a combination between size and instance id in its firstuint32
word. The size is limited to 64 k-Memory words, if this#define
is not set. If it is set, the operationsetSizeAndIdent_ObjectJc()
checks the size and sets some special bits to store a size of 1 M or 16 M memory words. Then the number of bits for instance id are reduced. It means there can only be 31 instances with > 1 Mwords, 255 instances > 64 kwords and 4095 instances < 64 kWords. The instance id is only necessary for special approaches, not obligate for all instances. Hence it is a possible restriction. It is possible for example to compile on a target platform withDEF_ObjectSimple_emC
with sizes till 128 kByte if the target uses 16-bit-memory addresses (the size counts memory addresses, not bytes), but compile the same sources for PC test withDEF_ObjectJc_LARGESIZE
to handle this data size.
5. ClassJc and Reflection handling
/**Define of the offering of Reflection information: */ #define DEF_REFLECTION_NO //#define DEF_REFLECTION_SIMPLE //#define DEF_REFLECTION_OFFS //#define DEF_REFLECTION_FULL
Only one define should be activated, all others should be commented.
The struct ClassJc
contains the type information for any data, it is referenced in
ObjectJc
. The ClassJc
can have a full capability to present full symbolic access
to all data (then DEF_REFLECTION_FULL
is present).
Or it is a small struct
only to support type check capability.
See ObjectJc.en.html, chapter Reflection and Types.
-
DEF_REFLECTION_NO
does not use anyClassJc
instances and is proper forDEF_ObjectSimple_emC
. -
DEF_REFLECTION_SIMPLE
reflects only the type of an instance and uses a simpleClassJc
definition, see ObjectJc_en.html#ObjectSimple. It can only be used This definition supports a simple inheritance. It means it can be detect whether an instance is type of a base class. That is necessary for type check in a base type for in derived instances. But only single inheritance is supported (often sufficient). -
DEF_REFLECTION_OFFS
: To prevent effort on target but allow symbolic data access via the ../Inspc/Inspector_en.html tool a inspector target proxy can be used. That proxy contains the textual information and communicates with the target via simple memory accesses. The target should contain generated Reflection information which contains only the offsets to all data in a struct, because the offsets may be specific on target compilation (cannot be presumed by a compiler- and situation-independent tool). It is especially for a poor target (less memory). Only single inheritance is supported. -
DEF_REFLECTION_FULL
: The reflection (see Reflection_en.html) contains the possibility of symbolic access to all data. It is similar as reflection in Java. The symbolic access can be used for the Inspector ../Inspc/Inspector_en.html as also for symbolic access inside the software, for example for commands to set specific parameter given as textual name and value. Multi inheritance is supported. This feature allows dynamic programming in C and C++, for example find out a data element because of its textual identifier name gotten via a communication telegram, or executed an operation by symbolic specification. For example symbolic data access via ../Inspc/Inspector_en.html can be used. That features are proper not only for PC programming but for rich powerful embedded applications. For that the symbolic information (reflection) should be generated from the header file information with the tool ../Inspc/CHeader2Reflection_en.html.
It is also possible to write specific sources for example with full reflection, including unconditional the .crefl
file, for example for internal symbolic access even to paramter fields, but usage elsewhere the _refloffs.c
file or only simple reflection.
The ClassJc
definition is simple if DEF_REFLECTION_FULL
is not defined. Then the definition is contained in <emC/Base/ObjectSimple_emC.h>
which is included anyway (not only if DEF_ObjectSimple_emC
is set). It contains a reference to the reflection offset table, if DEF_REFLECTION_OFFS
is set. It is only an int32
array.
The ClassJc
definition is contained in the automatic included <emC/Base/ClassJc_FullReflection_emC.h>
if the DEF_REFLECTION_FULL
is set.
More defines especially effective for ClassJc:
-
DEF_NO_StringUSAGE
: ThenClassJc
has not achar const*
string literal information about its type, only a number. Elsewhere it has a symbolic information about the type name, which can be used for debugging or for recognize the same type in different link units (dynamic linked libraries). The last case is important because more as one instance for the same type can be existing, and the types are equal though. IfDEF_REFLECTION_FULL
is set, the class works always with String information (the other definition in<emC/Base/ClassJc_FullReflection_emC.h>
). -
DEF_ClassJc_Vtbl
: This define enables virtual table with C approach also able to use in C++, using function pointer tables. Other than in C++ this virtual tables are well defined and visible in the user’s programming, so a safety check can be done (check of a significance text, possible check that is read only memory). But the user is responsible to write this tables. It may be possible to generate automatically this information too. The C++ virtual tables without safety check has the disadvantage, that the reference to thevtable
is immediately part of the data and can be disturbed or attacked. The mechanism ot thisVtblHeadJc
class is contained in
6. String capabilities
/**If set then the target should not use string operations */ #define DEF_NO_StringUSAGE //#define DEF_CharSeqJcCapabilities
-
#define DEF_NO_StringUSAGE
: If this is set, the usage of strings are prevented in some emC sources. This is for small or poor processors which don’t need String information and which have too less memory to store (not used) strings. For example theclassJc
struct is defined without the name of the type, only with a type identifier. For exception handling no textual information is stored (need space), only error numbers and line numbers.The
StringJc
type is nevertheless defined (unconditionally), the definition itself needs no space. It can be used, for example for very short string information in the user’s sources. It means this define is related firstly to some emC sources, but can also used in the user’s source.The header
emC/Base/StringBase.h
and the implementations are able to use, especially the basic string functions. The other String related emC sources (Base/String_emC.c
,Jc/StringJc.h
, some other ) and there implementations are disabled by this compiler switch. There capability cannot be used. -
#define DEF_CharSeqJcCapabilities
: If this is set, alsoDEF_REFLECTION_FULL
should be set, respectivelyDEF_ClassJc_Vtbl
. With this capability aStringJc
can also be aCharSeqJc
which offers routinescharAt_CharSeqJc(…)
,length_CharSeqJc()
andsubSequence_CharSeqJc(…)
. This three routines are defined in Java also injava.lang.CharSequence
. It is possible to get characters from any instance which implements this interface. TheCharSeqJc
is defined for C usage withoutvirtual
operations of C++, see Virtual Operations in C++, alternatives, chapter Solution: Vtbl referenced from reflection -
If both definitions are not set,
StringJc
is used, some functionality is used, depending on the sources. -
DEF_ClassJc_Vtbl
This is an extra define which can only used withDEF_REFLECTION_FULL
. It enables an adequate 'virtual table' for C programming using the reflection data structure. This is some more complex than a C++ virtual, but more safe. It is used for aCharSeqJc
and also in some special sources (Inspector) which were translated from Java. ACharSeqJc
has the same format as aStringJc
. It is aStringJc
if only a const String is referenced, determined by some bits. But it can act as interface to any specific class (asjava.lang.CharSequence
in comparison withjava.lang.String
). In this case the length element in thestruct
contains the index to the correct operation set for theCharSequence
virtual table inside the whole table, referenced from the reflection. Theaddr
part contains the instance address of this data.
7. Exception and ThreadContext
For exception handling see ThCxtExc_emC.html: Stacktrace, ThreadContext and Exception handling.
The Strategy is: Test on PC with full exception handling, deploy maybe in a poor target
well tested without exception, but with unchanged sources.
To control the exception handling and meaning of THROW
, macros are used.
The ThreadContext contains thread-local or interupt-local data. Also an interrupt in a poor target without RTOS is a thread. The switch of thread context is very simple, see ThCxtExc_emC.html#_thCxt.
/**If set, without complex thread context, without Stacktrace*/ #define DEF_NO_THCXT_STACKTRC_EXC_emC //#define DEF_ThreadContext_NO_STACKTRC_emC //#define DEF_ThreadContext_STACKUSAGE //#define DEF_ThreadContext_STACKTRC /**The following compiler switch can be applicate independently with all three above: * It clarifies that there is a thread local heap which offers some more possibiities * for memory allocation valid in one thread respectively Stack usage. */ //#define DEF_ThreadContext_HEAP_emC
-
DEF_NO_THCXT_STACKTRC_EXC_emC
This define is also related to the Exception Handling. All is switched of, not able to use. This is for startup using emC. -
DEF_ThreadContext_NO_STACKTRC
If this#define
is set the macrosSTACKTRC_ENTRY(name)
etc. are all empty. It means this macros can be used any time, also for a very poor system, it does not produce code under this condition. The exception handling can be used nevertheless because it does not need the stack trace, it does need only the ThreadContext for thread related data. This is also a storage for theExcpetionJc
data to store an exception to evaluate it in a calling environment, also ifDEF_NO_Exception_emC
orDEF_Exception_Log_emC
is set.The
ThreadContext_emC_s
itself should be seen as mandatory, necessary for Exception handling. -
DEF_ThreadContext_STACKUSAGE
If this#define
is set the macrosSTACKTRC_ENTRY(name)
etc. only write the current stack pointer in theThreadContext_emC_s
and calculates the maximum. It is a possibility to track the stack usage on debug on runtime. This feature is also activated onDEF_ThreadContext_STACKTRC
. -
DEF_ThreadContext_STACKTRC
If this#define
is set the ThreadContext contains a Stacktrace with given number of levels on its initialization, see ThCxtExc_emC.html#_thCxt. It enables tracking from where a routine was called which has an exception (similar to Java). A Stacktrace level needs two references to the filename and operation name and oneint
for the line. It is about 10 bytes in a 16-bit system with 32 bit addresses. It may be also possible for systems with less memory, if only less levels are used. The Stacktrace does not overflow, on overflow only the last level and the first levels are visible. But on poor targets the number of nested calls may be less anyway. -
DEF_ThreadContext_HEAP_emC
The ThreadContext has also space for some thread local dynamic data. Especially with that an exception message can be prepared in the stack and transferred to this threadlocal heap to help working with elaborately messages, without organization of an extra space. But this parts should be controlled by#ifdef DEF_ThreadContext_HEAP_emC
with an#else
branch with a simple replacing const string literal. This#define
can be set independent of the other.
#define DEF_NO_Exception_emC //#define DEF_Exception_Log_emC //#define DEF_Exception_longjmp //#define DEF_Exception_TRYCpp
Only one of this #define
should be activated. See ThCxtExc_emC.html.
If some sources should be used different exception handling approaches, it can be changed compiling-unit specific (in the source.c file itself or as compiler option). If a source uses try
catch
in original C++ kind, it is not affected by these settings.
-
DEF_Exception_TRYCpp
: The C++ Compilation should be used, especially on PC-Test. The emC-Exception handling withTRY CATCH THROW
(see ThCxtExc_emC.html) uses the C++try catch throw
Keywords. A catch is always implemented as the 'native C++catch(…)’ which is necessary for the Visual Studio 'asynchronous exceptions'. They are handled if the compiler switch `/EHa
is set. See https://docs.microsoft.com/de-de/cpp/build/reference/eh-exception-handling-model It means, memory errors because faulty pointers, division by zero etc. forces catching this exception too. It may be substantial for programs in test. (TODO clarify this topic for gcc compilation.) -
DEF_Exception_longjmp
: Thelongjmp
mechanism is used for the emC-Exception handling withTRY CATCH THROW
. C or C++ compilation is possible. If C++ is used, the destructors are not called on THROW → CATCH. It means they should not contain necessary code. Hence this mode should only be used if temporary class instances are not used or all of their destructors are empty. On a target system this condition may be true, thelongjmp
exception handling is some time faster. For closing resources aFINALLY
clause can be used anytime, instead do this in the destructor. This is the Java language approach, and runs also well in the emC exception handling with the given macro system. A TRY-FINALLY can be used (without CATCH block) for closing things. Stack local data of lept levels are simple unloading (also class instances) without any code execution. -
DEF_Exception_Log_emC
andDEF_NO_Exception_emC
: It is for 'well tested' sources. TheTHROW
macro inside the user sources calls a log output (can write some small information somewhere in the memory). The operation does not return, if the return is not programmed. The execution continues afterTHROW
. But an information in the stack trace is written, so theCATCH
block after the normal return is entered. It means the replacement is done though, only the abort of execution is not done.
8. Assertion
The C++ assert()
macro acts depending on too much system header specificas. Hence the macro
ASSERT_emC(Condition, text, value1, value2)
is preferred to use in an application and is used in the emC sources.
//If set, no assertion is done: #define ASSERT_IGNORE_emC
-
ASSERT_IGNORE_emC
: If this compiler switch is set, allASSERT_emC(…)
macros are empty. It means, theASSERT_emC(…)
macro does not produce any code, also the text is not produce. It is for tested systems. -
If this
#define
is not set, theASSERT_emC(…)
macro produces aTHROW
if the condition is false. It means it uses the existing exception handling with its settings.
See …TODO assert_emC.html
9. Blockheap usage
The emC/Blockheap/*
are a set of sources which supports a heap with equal size blocks. It prevents fragmentation and supports working with some dynamic memory.
/**Selects working with Blockheap*/ //#define USE_BlockHeap_emC //#define DEF_BlockHeap_GARBAGECOLLECTOR
10. Definitions for VALTYPE_AddrVal_emC and StringJc-mask
You can define the type of the value in a AddrVal_emC
typed structure.
This type should depend on the platform and the requirements of the application
(sizes of data).
Often and per default int32
is used, which is proper for 32 bit systems.
But for small memory and less requirements, also 16 bit may be sufficient as special case.
Only in that case it should be defined:
/**Defines the type for the length or value in a struct{ addr, val} defined with STRUCT_AddrVal_emC(...). */ #define VALTYPE_AddrVal_emC int32
If this definition is missing, the default int32
is valid.
This is often the good choice:
For a 16 bit Platform adequate or matching to that definition the following should be set:
#define mLength_StringJc 0x03ff
This should match to the VALTYPE_AddrVal_emC
.
In this case it means the maximum of length of a StringJc
is limited to 1023.
It is a condition of the application.
11. Handle instead address as reference
A possible solution for references is usage of a handle instead the real memory address. Before access to the memory of course the handle should be transformed to the address. But as argument of operations, as stored reference in data etc. the handle can be used. This is especially done for Simulink function block connections which are really references between blocks or other data, which cannot be presented as address value in Simulink. One other reason to do so is: On Embedded platforms an address is often a 32 bit value, but for PC simulation of the same model an address needs 64 bit but 64 bit should not be used in data structures which should be compatible between the platforms. An similar approach is given if data with references should be exchange between platforms.
In some 64-bit-Applications, for example S-Functions in Simulink,
all memory addresses of instances (…of Function Blocks) are held in a global accessable
address table. The references are handles - index to the table, as uint32
word.
For deployment the code to a 32-bit-System the same uint32
words
as connection data between function blocks (aggregations in UML-slang) contains
the really memory addresses, for fast access. This is regarded by code generation
in Simulink (® Mathworks) - via specific tlc files (tlc = target language control).
The handle value is an index as int value to a global address table (an array). The association from an handle value to the address is very simple and fast, only the access to the global address array is necessary. For fast execution on a small target system the handle is the address itself (32 bit), so no translation is necessary.
If the following identifier is set in the applstdef_emC.h
the HandleADDR_emC(TYPE)
is presented by the defined integer type. It can be also uint16
if handles should have only 16 bit, maybe for an application should run on a small 64k address space processor:
//To work with handle instead pointer in data struct and #define DEF_Type_HandleADDR_emC uint32 #define DEFINED_nrEntries_Handle2Ptr 1000 //#define DEF_HandlePtr64
If this identifier is not defined, the following definitions are made in the afterwards included emC/Base/types_def_common.h
:
#ifdef DEF_Type_HandleADDR_emC //... #else //not DEF_Type_HandleADDR_emC #define HandleADDR_emC(TYPE) TYPE* #define addr_HandleADDR_emC(HANDLE, TYPE) (HANDLE) #define handle_HandleADDR_emC(HANDLE) ((intPTR)(HANDLE)) ... #endif //DEF_HandlePtr64
It defines the HandleADDR_emC(TYPE)
construct as simple type reference. If the handle as integer should be dedicated used, it offers an intPTR
which is a proper int
able to present the memory address. It is simple convertible back to the address. This int
representation may be 16, 32 or 64 bit depending on the platform. It is true 16 bit for small processors with less than 64 k address space.
The access of the address with given handle is very simple. The TYPE
parameter is ignored, it should be the same as in the HandleADDR_emC(TYPE)
definition.
If the handle type is defined, the emC/Base/types_def_common.h
determines:
#ifdef DEF_Type_HandleADDR_emC #define HandleADDR_emC(TYPE) DEF_Type_HandleADDR_emC //Note: <emC/Base/types_def_common.h> should be included before in this file. #include <emC/Base/Handle_ptr64_emC.h>
It means the defined handle type is used. The rest is defined in the specific emC/Base/Handle_ptr64_emC.h
. This file defines the strategy to convert the address to the handle, and back again.
12. Specification of safety areas for alloc_MemC()
Allocation is a specific problem. One of the problems is: A programming error can write beyond the memory limits and destroy the whole heap organization. This problem may solved in modern C++ programming (may, not is, it depends on the errors).
Another problem is: Embedded software may need more as one heap area for different tasks, respecitively there are different memory areas in a controller. Hence the simple standard malloc
or new
is not enough sufficient. new
can be overridden in C++ by an own operator new
. Instead malloc
the emC offers void* alloc_MemC(int size)
(emC/Base/MemC_emC.h
) and a proper os_allocMem(size)
which can deliver target specific. MS-Windows offers in its API a LocalAlloc(…)
(WinBase.h
). All in all it means, the standard-C malloc
is not the only one possibility to alloc.
//#define sizeSafetyArea_allocMemC 256
If this #define
is activated, the given number of memory locations are added to all allocations. It is for experience. It is possible to set this #define
in a specific source and only under debug conditions.
13. Usage C++
C-source can be compiled with C++ compilation. Usual there should be no problems, else the C++ compiler detects more errors of the programming, really errors which should be corrected.
But an algorithm should be proper for C compilation if the target should require it. The same sources can be compile with C++ in a test environment or on another target.
The decision between C and C++ compilation is done with compiler options, it is /TP
for Visual Studio and -x c++
for GNU compiler, or via the make files. The C++ compilation sets a #define __cplusplus
internally, which can be checked in the sources.
The user’s sources, especially reused parts, can contains both, C routines, C struct
and C++ classes for usage. See ObjectJc_en.html#Cpp. But not only the #ifdef __cplusplus
should decide for usage the classes, else
#define DEF_cplusplus_emC #define DEF_CPP_COMPILE
should be checked. The first one is used inside emC sources. The second one can be used more for the application sources. Both should be set similar.
If C++-Projects are mixed with c-compiled sources, a correct handling of extern "C"
is necessary. All Functions which are implemented in C-Sources
should be declared in the header with
extern_C Type myOperation_Type(...); //always as C-functions .... extern_CCpp Type myOperation_Type(...); //defined depending DEF_CPP_COMPILE
The extern_C
is replaced by extern "C"
for C++-compilation.
That prefix forces a C-like Linker label with only the name of the operation,
without argument-sensitivity (signature of the operation). A C-compiled object file
contains this simple label only. The C++ linker regards it.
The second form regards the compiler switch DEF_CPP_COMPILE
. Only if it is not set
then the macro extern_CCpp
is defined as extern "C"
.
Elsewhere it assumes that the associated c-source is compiled with C++.
The call of the operation in a C++ environment expects a linker label with argument
sensitivity (signature of the operation). It should be offered by the C-routine
and requests the C++ compilation for C-sources.
There may be some source which are never compiled with C++ because there are very simple
(then C++ is never necessary) or they define const
-data for a const memory segment
(for example immediately contained and read from a Flash Memory in an embedded device).
For that sources extern_C
should be used anyway.
14. Standard headers
The following headers to include in applstdef_emC.h
, so all sources can uses its features.
#include <compl_adaption.h> //#include <emC/Base/types_def_common.h> //#include <emC_srcApplSpec/applConv/EnhanceRef_simple.h> //#include <emC/BlockHeap/BlockHeap_emC.h> //#include <emC/Base/Assert_emC.h> #include <emC/Base/applstdef_common.h>
The following rules are valid:
-
The
compl_adaption.h
is (should be) independent ofapplstdef_emC.h
. It means it must not contain defines which are set in theapplstdef_emC.h
It means it can be also included on start ofapplstdef_emC.h
or before in a compilation unit. -
The
emC/Base/types_def_common.h
should be included inside thecompl_adaption.h
. It builds one unit, the compiler- and target-specificcompl_adaption.h
and the resulting common definition for types. Hence thecompl_adaption.h
can be included as own in a source if this source does not depend on any settings inapplstdef_emC.h
. Here the commented include is only a marker. Twice including is prevented by header guards, it is only business for the compiler. -
emC_srcApplSpec/applConv/EnhanceRef_simple.h
may be included, or a proper other file is included, for example the followingBlockHeap_emC.h
. If this file is not included, its definitions where done inapplstdef_default.h
. -
emC/BlockHeap/BlockHeap_emC.h
: If this file is included, theBlockHeap
concept is used, see todo as you see the BlockHeap concept should be described and tested still. It is for embedded Hardware which needs small portions of allocated memory. To get the same size for all, a so named "fragmentation" of memory is prevented. -
emC/Base/Assert_emC.h
: This is also only a placeholder. The named file is included always inapplstdef_default.h
. But you can include here a specific file with the adequate ASSERT… macros. -
applstdef_common.h
: This is required to include. This file contains common definitions for the application based on the before set defines.
15. reflOffs.h
A *_reflOffs.c
file is used for a symbolic access to some or all data but without symbolic in the (poor) target, via InspcTargetProxy. This files have to be generated for the whole application. The header file *_reflOffs.h
should be known by a lot of sources. The sources cannot know which file is it because the name depends on the application, not on the reused source. Hence it should be included in the applstdef_emC.h
which is responsible to the whole application.
The disadvantage, re-compile unnecessary files (which does not use this information) only if the content of the *_reflOffs.h
is changed, is not so problematic. The generation of the reflection files is started manually often, then a 'build all' should be done anyway.
Additionally it can be included:
//including the project specific reflOffs.h defines DEF_REFLECTION_OFFS #ifdef DEF_REFLECTION_OFFS //contains DEF_REFLOFFS_...for all defined ClassJc #include <emC_Exmpl_Ctrl/genRefl/emC_Exmpl_Ctrl_reflOffs.cpp.h> //Note: the adequate *.reloffs.c should be part of the project: #endif
The included header is valid for the whole application and defines which ClassJc
instances are delivered by a *_reflOffs.c
file. This can be select in the sources, to define only then ClassJc
if necessary:
//Example for a C-file: #ifdef DEF_REFLECTION_FULL #include "genRefl/Test_Ctrl.crefl" #elif !defined(DEFINED_refl_Test_Ctrl) && !defined(DEF_REFLECTION_NO) ClassJc const refl_Base_Test_Ctrl = INIZ_ClassJc(refl_Base_Test_Ctrl, "Base_Test_Ctrl"); ClassJc const refl_Test_Ctrl = INIZsuper_ClassJc(refl_Test_Ctrl, "Test_Ctrl", &refl_Base_Test_Ctrl); #endif
For this example the DEFINED_refl_Test_Ctrl
may defined in the emc_Exmpl_Ctrl_reflOffs.h
, then the twice definition is prevented.
16. Some more specifics
The applstdef_emC.h
can contain application specific definitions. For example the Test_emC\IDE\VS15\applstdef_CppObj\applstdef_emC.h
contains definitions, which main routine should be used for a manual test, or select with the Test gui:
// //What to start as main: // #define DEF_TESTBasics_emC //#define DEF_TESTALL_emC //this is the setting for the autmatic test. //#define DEF_MAIN_emC_TestAll_testSpecialMain //#define DEF_MAIN_testMain_ObjectJc //#define DEF_MAIN_TestCtrl_emC
A main routine can be written in
#ifdef DEF_MAIN_TestCtrl_emC int main(int nArgs, char** sArgs) { .... } #endif
In this kind the application sources can contain more as one main entry, activated with the compiler switch.
17. Example
This is the example of Test_emC/src/main/cpp/src_emC/emC_inclApplSpec/stdef_ApplCpp64/applstdef_emC.h
.
This is the currently used applstdef_emC
for test on PC in Visual Studio,
hence some special settings may be done.
The special features for this file is:
-
Firstly you see some tags which are used for this documentation. It is not necessary for application.
-
Secondly you see:
#define ASSERT_Test_emC //includes the file which is generated from the simulati selector: #include "emC_TestAll/fDefSelection.h" #ifndef DEFINED_fDefSelection //....
This is for test. The so named "Stimuli Selector" ../../../StimuliSel/html/StimuliSel.html
contains some test conditions. It produces the include file also with manual handling
as well as automatically by the test scripts to test all combibation,
which are following excluded if DEFINED_fDefSelection
is set.
Now the whole content of for copy and paste and adapt in the moment of generation this docu via Asciidoc:
#ifndef HGUARD_applstdef_emC #define HGUARD_applstdef_emC //Projectspecific applstdef_emC.h /**It seems to be a specifica in Visual Studio. * The VS-File Microsoft Visual Studio 14.0\VC\include\yvals.h * contains a assert-message with is prevented with this define. * What ist it, what means it? not clarified yet. * Note: This applstdef_emC.h is only for the visual studio project. */ #define _ALLOW_RTCc_IN_STL //what is it? a specialism of Visual Studio?? //tag::stimuli[] #define ASSERT_Test_emC //includes the file which is generated from the simulati selector: #include "emC_TestAll/fDefSelection.h" #ifndef DEFINED_fDefSelection //.... //end::stimuli[] //tag::ObjectJc[] /**Define the granularity of the ObjectJc base class: */ #define DEF_NO_ObjectJc_emC //#define DEF_ObjectSimple_emC //#define DEF_ObjectJc_SYNCHANDLE //#define DEF_ObjectJcpp_REFLECTION //#define DEF_ObjectJc_OWNADDRESS //#define DEF_ObjectJc_LARGESIZE //tag::Refl[] /**Define of the offering of Reflection information: */ #define DEF_REFLECTION_NO //#define DEF_REFLECTION_SIMPLE //#define DEF_REFLECTION_OFFS //#define DEF_REFLECTION_FULL //end::Refl[] //end::ObjectJc[] //tag::StringJc[] /**If set then the target should not use string operations */ #define DEF_NO_StringUSAGE //#define DEF_CharSeqJcCapabilities //end::StringJc[] //tag::ThCxt[] /**If set, without complex thread context, without Stacktrace*/ #define DEF_NO_THCXT_STACKTRC_EXC_emC //#define DEF_ThreadContext_NO_STACKTRC_emC //#define DEF_ThreadContext_STACKUSAGE //#define DEF_ThreadContext_STACKTRC /**The following compiler switch can be applicate independently with all three above: * It clarifies that there is a thread local heap which offers some more possibiities * for memory allocation valid in one thread respectively Stack usage. */ //#define DEF_ThreadContext_HEAP_emC //end::ThCxt[] //tag::Exc[] #define DEF_NO_Exception_emC //#define DEF_Exception_Log_emC //#define DEF_Exception_longjmp //#define DEF_Exception_TRYCpp //end::Exc[] //tag::assert[] //If set, no assertion is done: #define ASSERT_IGNORE_emC //end::assert[] //tag::Blockheap[] /**Selects working with Blockheap*/ //#define USE_BlockHeap_emC //#define DEF_BlockHeap_GARBAGECOLLECTOR //end::Blockheap[] //tag::HandleAddr[] //To work with handle instead pointer in data struct and #define DEF_Type_HandleADDR_emC uint32 #define DEFINED_nrEntries_Handle2Ptr 1000 //#define DEF_HandlePtr64 //end::HandleAddr[] // //What to start as main: // #ifndef DEF_TESTBasics_emC /**select only one of this to debug special tests: */ //#define DEF_TESTBasics_emC //#define DEF_TESTALL_emC //this is the setting for the autmatic test. //#define DEF_MAIN_emC_TestAll_testSpecialMain //#define DEF_MAIN_testMain_ObjectJc #define DEF_MAIN_TestCtrl_emC #endif //ndef DEF_TESTALL_emC #endif //DEFINED_fDefSelection //tag::AddrVal[] /**Defines the type for the length or value in a struct{ addr, val} defined with STRUCT_AddrVal_emC(...). */ #define VALTYPE_AddrVal_emC int32 //end::AddrVal[] //tag::StringJcLen[] /**Bits of length of constant string adequate to VALTYPE_AddrVal_emC. * It have to be a mask with set bits on right side (all last significant bits). * The next 2 bits left are used internally for designation of String. * see [[mNonPersists__StringJc]], [[mThreadContext__StringJc]]. * See also [[kIsCharSequence_StringJc]] * The following bits left side are used for enhanced references, see kBitBackRef_ObjectJc and mBackRef_ObjectJc. * If enhanced references are not used, a StringJc can occupy all bits, for example all 16 bits for 16-bit-integer systems. */ #define mLength_StringJc 0x00003fff //end::StringJcLen[] //tag::UseCpp[] /**This is to compile C++ classes of emC if __cplusplus is set. For C compilation this is ineffective because __cplusplus is necessary too*/ #define USE_cplusplus_emC #define DEF_cplusplus_emC #define DEF_CPP_COMPILE //end::UseCpp[] #define DEFINED_getVarAddrType_CalcExpr //tag::specSizes[] #define kMaxPathLength_FileDescription_OSAL 512 #define sizeSafetyArea_allocMemC 256 //end::specSizes[] //tag::includes[] #include <compl_adaption.h> //#include <emC/Base/types_def_common.h> //#include <emC_srcApplSpec/applConv/EnhanceRef_simple.h> //#include <emC/BlockHeap/BlockHeap_emC.h> //#include <emC/Base/Assert_emC.h> #include <emC/Base/applstdef_common.h> //end::includes[] //tag::reflOffs[] //including the project specific reflOffs.h defines DEF_REFLECTION_OFFS #ifdef DEF_REFLECTION_OFFS //contains DEF_REFLOFFS_...for all defined ClassJc #include <emC_Exmpl_Ctrl/genRefl/emC_Exmpl_Ctrl_reflOffs.cpp.h> //Note: the adequate *.reloffs.c should be part of the project: #endif //end::reflOffs[] #endif //HGUARD_applstdef_emC