9.10 Compiler-Specific Type Qualifiers - C++
The C++ language does not support additional type qualifiers such as named address
spaces and _Fract or _Accum . These features are
simply not available when compiled with a C++ compiler, even if they are wrapped in an
extern "C" block.
For MPLAB® XC-DSC C++
Compiler for dsPIC33C/E/F and dsPIC30 DSC these type qualifiers are the extended address space
qualifiers such as __prog__ and __eds__. The
space attribute which defines the allocation requirements is available
in C++.
Our recommend approach is to use function accessors written in C and call these from C++;
these accessor functions should be prototyped in C++ within an extern "C"
block.
In the following brief example, we intend to place a data table in the PSV section and share this table with C++ code in other modules. There are 2 main aspects on the 'C' side, the declaration (prototypes) and the implementation. We share an example C++ code that safely uses this data.
Declarations - interface.h
#ifndef _INTERFACE_H_
#define _INTERFACE_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* access function */
extern const char *PSV_read_char_ptr_from(uint32_t handle, int index);
/* an opaque type of suitable size; usually 'void *' would be used */
extern uint32_t handle_1;
extern uint32_t handle_2;
#ifdef __cplusplus
}
#endif
#endif
Implementation - implementation.c
#include <stdio.h>
#include "interface.h"
/* a __psv__ pointer to a const char (in data space) */
static const char * __psv__ data1[] __attribute__((space(psv))) = {
"Hello World",
"Is there anybody out there?",
"En Fin!"
};
static const char * __psv__ data2[] __attribute__((space(psv))) = {
"Bonjour le monde",
"Il y a quelqu'un?",
"The end!"
};
uint32_t handle_1 = 0;
uint32_t handle_2 = 0;
void __attribute__((user_init)) implementation_init(void) {
/* cannot initialise this statically
* - user_init attribute is a way to do C++ static initialisation from C
*/
handle_1 = (uint32_t)data1;
handle_2 = (uint32_t)data2;
}
const char * PSV_read_char_ptr_from(uint32_t handle, int index) {
char * __psv__ *p = (char * __psv__ *)handle;
if (index < 0) return 0;
return p[index];
}
C++ use - main.cpp
#include <stdio.h>
#include "interface.h"
int main(void) {
for (int index = 0; index < 3; index++) {
char *p = PSV_read_char_ptr_from(handle_1,index);
fprintf(stderr,"message %d: %p %s\n", index, p, p);
}
for (int index = 0; index < 3; index++) {
char *p = PSV_read_char_ptr_from(handle_2,index);
fprintf(stderr,"message %d: %p %s\n", index, p, p);
}
return 0;
}
Compilation steps
Compilation is straight forward; compile the C program with the C compiler, compile the C++
program with the C++ compiler and link the resulting objects together. There is one caveat:
for historical reasons the C compiler defaults to -fshort-double but the
C++ compiler does not support that. Be sure use the -fno-short-double
option with C compiled source when intermixing.
xc-dsc-gcc -c implementation.c -O1 -mcpu=30F6014 -fno-short-doublexc-dsc-g++ implementation.o main.cpp -O1-mcpu=30F6014
Executing this in the simulator should display the following, addresses may change:
message 0: 9050 Hello World
message 1: 905c Is there anybody out there?
message 2: 9078 En Fin!
message 0: 9024 Bonjour le monde
message 1: 9035 Il y a quelqu'un?
message 2: 9047 The end!
