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_ObjectSimple_emC
//#define DEF_ObjectJcpp_REFLECTION
//#define DEF_ObjectJc_SYNCHANDLE
//#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.

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 and DEF_REFLECTION_NO decide that an ObjectJc in <emC/Base/ObjectSimple_emC.h> is minimalistic. It contains only an int32 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 than DEF_REFLECTION_NO should be used.

  • DEF_ObjectSimple_emC set with either DEF_REFLECTION_SIMPLE or DEF_REFLECTION_OFFS decide that an ObjectJc has a reference to a simple ClassJc instance. If DEF_REFLECTION_SIMPLE is given, only a simple type test is possible, but with base type check. If DEF_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 a static_cast<MyBaseType> on class usage or a simple C cast from the ObjectJc* 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 for ObjectJc in 32-bit-systems.

  • If DEF_ObjectSimple_emC is given, the other DEF_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 the ObjectJc data contains an offset from instance address to the ObjectJc data. This is necessary for C++ usage of reflection information, if the C++ classes uses virtual tables multi inheritance. Then the ObjectJc is not on position 0 of the class. The offsets of fields in the reflection information are related to the ObjectJc. 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 get ObjectJc 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 on ObjectJc-containing types using reflection access. If it is combined with DEF_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 the ObjectJc 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: The ObjectJc has always a combination between size and instance id in its first uint32 word. The size is limited to 64 k-Memory words, if this #define is not set. If it is set, the operation setSizeAndIdent_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 with DEF_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 with DEF_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 any ClassJc instances and is proper for DEF_ObjectSimple_emC.

  • DEF_REFLECTION_SIMPLE reflects only the type of an instance and uses a simple ClassJc 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: Then ClassJc has not a char 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. If DEF_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 the vtable is immediately part of the data and can be disturbed or attacked. The mechanism ot this VtblHeadJc class is contained in

6. String capabilities

/**If set then the target should not use string operations */
//#define DEF_NO_StringUSAGE
//#define DEF_NO_StringJcCapabilities

This is a possibility to prevent effort for Strings in a poor target. For example a ClassJc contains the name as String (char const*) , but not if this #define is set. It saves some memory.

An poor target is often used only for numeric calculations. Adequate for a DSP processor (Digital Signal Processor). Often such CPUs are combined on the same board with a organization and communication processor which uses Strings of course.

  • DEF_NO_StringUSAGE prevents usage of string literals (char const* elements) in emC-Sources, for only numeric usage. The application can use String operations of course in its own decision, or can check this #define in the application too to difference between platforms and reduce functionality.

  • DEF_NO_StringJcCapabilities reduces the possibilities of a StringJc. This is a small struct which contains the char const* pointer to a String maybe in stack, heap or const, its length (the string itself need not be null-terminated) and some special bits. The struct StringJc is anyway existing, but its capability is reduces. See Header for details.

  • DEF_ClassJc_Vtbl This is an extra define which can only used with DEF_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 a CharSeqJc and also in some special sources (Inspector) which were translated from Java. A CharSeqJc has the same format as a StringJc. It is a StringJc if only a const String is referenced, determined by some bits. But it can act as interface to any specific class (as java.lang.CharSequence in comparison with java.lang.String). In this case the length element in the struct contains the index to the correct operation set for the CharSequence virtual table inside the whole table, referenced from the reflection. The addr 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_ThreadContext HEAP_emC
//#define DEF_ThreadContext_STACKTRC
//#define DEF_ThreadContext_STACKUSAGE
#define DEF_ThreadContext_STACKTRC_NO

The ThreadContext_emC_s itself should be seen as mandatory, necessary for Exception handling.

  • 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 elobaretely 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 relplacing const string literal. This #define can be set independent of the other.

  • 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 one int 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_STACKUSAGE If this #define is set the macros STACKTRC_ENTRY(name) etc. only write the current stack pointer in the ThreadContext_emC_s and calculates the maximum. It is a possibility to track the stack usage on debug on runtime. This feature is also activated on DEF_ThreadContext_STACKTRC.

  • DEF_ThreadContext_STACKTRC_NO If this #define is set the macros STACKTRC_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.

    //#define DEF_Exception_TRYCpp
    #define DEF_Exception_longjmp
    //#define DEF_Exception_NO

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 with TRY 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 A longjmp is used in the TRY-CATCH-THROW macros. If C++ is used, the destructors are not called on THROW → CATCH. It means it should not contain necessary code.

  • DEF_Exception_longjmp: The longjmp mechanism is used for the emC-Exception handling with TRY CATCH THROW. C or C++ compilation is possible, whereby for C++ sources destructors are not invoked on THROW. 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, the longjmp exception handling is some time faster. For closing resources a FINALLY 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_NO: It is for 'well tested' sources. The THROW 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 after THROW. But an information in the stack trace is written, so the CATCH 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, the ASSERT_emC(…​) macro is empty. It means, the ASSERT_emC(…​) macro does not produce any code, also the text is not produce. It is for tested systems.

  • If this #define is not set, the ASSERT_emC(…​) macro produces a THROW 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

The header file emC/Base/types_def_common.h defines a macro:

#define STRUCT_AddrVal_emC(NAME, TYPE) struct NAME##_T { TYPE* addr; VALTYPE_AddrVal_emC val; } NAME

With this macro typical small struct can be defined which contains a memory address together with a integer value. The value can often present the size of a memory part or the number of elements of an array. For example

typedef STRUCT_AddrVal_emC(floatARRAY, float);

defines such a struct for a float array as

struct floatARRAY_T { float* addr; int32 val; } floatARRAY;

The intension to do so is, often a size or length information to an array reference is stored anywhere other. It is better to bind both parts. It is a simple and effective C approach. A second, original intension is: Older compiler had returned such a struct by value in two processor register. Modern compiler also more complex structures are well handled, but the approach is proper though. An instance can deliver as call-by-value argument too. It means, address and length are bind together in all cases.

Yet the type of the value 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

#define VALTYPE_AddrVal_emC int16

the given type is used, for example for a small 16 bit processor with 64 kByte address space (hence the address has only 16 bit).

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:

#define DEF_Type_HandleADDR_emC uint32

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/Assert_emC.h>
#include <emC_srcApplSpec/applConv/EnhanceRef_simple.h>
#include <emC/Base/Exception_emC.h>

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.h>
 //Note: the adequate *_reloffs.c should be part of the project:
#elif defined(DEF_REFLECTION_FULL)
 #define DEF_ClassJc_Vtbl    //It is used in the inspector sources
#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\IDE\VS15\applstdef_CppObj\applstdef_emC.h, of course under development (2021-05-02)

#ifndef HGUARD_applstdef_emC
#define HGUARD_applstdef_emC

//Projectspecific applstdef_emC.h

//includes the file which is generated from the simulation selector.
//It sets this #defines depending on the selection instead manual set.
//Uncomment it if SimSelector should be used.
//#include "emC_TestAll/fDefSelection.h"

#ifndef DEFINED_fDefSelection       //manual settings:

/**Define the granularity of the ObjectJc base class: */
//#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


/**If set then the target should not use string operations */
//#define DEF_NO_StringUSAGE
//#define DEF_NO_StringJcCapabilities


/**If set, without complex thread context, without Stacktrace*/
#define DEF_ThreadContext_HEAP_emC
#define DEF_ThreadContext_STACKTRC
//#define DEF_ThreadContext_STACKUSAGE
//#define DEF_ThreadContext_STACKTRC_NO

#define DEF_Exception_TRYCpp
//#define DEF_Exception_longjmp
//#define DEF_Exception_NO


//If set, no assertion is done:
//#define ASSERT_IGNORE_emC

/**Selects working with Blockheap*/
//#define USE_BlockHeap_emC
//#define DEF_BlockHeap_GARBAGECOLLECTOR


//To work with handle instead pointer in data struct and
#define DEF_Type_HandleADDR_emC uint32
#define DEFINED_nrEntries_Handle2Ptr 1000
//#define DEF_HandlePtr64

//
//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

//for struct{ addr, val}:
#define VALTYPE_AddrVal_emC int32
/**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




/**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


#define DEFINED_getVarAddrType_CalcExpr

#define kMaxPathLength_FileDescription_OSAL 512
#define sizeSafetyArea_allocMemC 256


#include <compl_adaption.h>
#include <emC/Base/Assert_emC.h>
#include <emC_srcApplSpec/applConv/EnhanceRef_simple.h>
#include <emC/Base/Exception_emC.h>



//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

#endif //HGUARD_applstdef_emC