How to get rid of "undefined reference to 'Class::member'"? in conjunction with initialization of an array - c++11

When building my code I get the following "undefined reference"-errors, which I cannot get rid of. I've already tried several hints from stack overflow but nothing helps :-(. Maybe you have an idea?
I use VSCode with PlatformIO for an Arduino Uno on Mac OS.
in function `get7SegBitMap':
/Users/christian/Projekt/src/charmap7seg.cpp:70: undefined reference to 'Led7SegmentCharMap::bitMap'
/Users/christian/Projekt/src/charmap7seg.cpp:70: undefined reference to `Led7SegmentCharMap::bitMap'
collect2: error: ld returned 1 exit status
The hierarchy is:
main.cpp includes ledmatrix.hpp
ledmatrix.cpp includes ledmatrix.hpp
ledmatrix.hpp includes charmap7seg.hpp
charmap7seg.cpp includes charmap7seg.hpp
charmap7seg.hpp
#pragma once
#include <Arduino.h>
class Led7SegmentCharMap {
private:
static const uint8_t bitMap[]; // will be initialized in cpp-file
uint8_t getCharMapIndex(const unsigned char outChar);
public:
// Konstruktur
Led7SegmentCharMap();
// BitMap zur Darstellung auf der 7-Segment-Anzeige für outChar ermitteln
uint8_t get7SegBitMap(const unsigned char outChar);
};
int set7SegValue(const LedMatrixPos pos, const uint8_t charBitMap);
charmap7seg.cpp
#include <Arduino.h>
#include <charmap7seg.hpp>
// Konstruktur
Led7SegmentCharMap::Led7SegmentCharMap() {
uint8_t bitMap[] = { ///< charMap contains bitmaps for 7-seg-displays
//gfedcba
0b0111111, ///< "0": Segments f, e, d, c, b, a --> bitMap[0]
0b0000110, ///< "1": Segments c, b --> bitMap[1]
0b1011011, ///< "2": Segments g, e, d, b, a --> bitMap[2]
(...)
}
(void)bitMap; // to suppress the compiler warning "unused variable"
};
uint8_t Led7SegmentCharMap::get7SegBitMap(const unsigned char outChar) {
return bitMap[getCharMapIndex(outChar)]; // <===== this is line 70
};
(...)
ledmatrix.hpp
#pragma once
#include <Arduino.h>
#include <charmap7seg.hpp>
class LedMatrix {
private:
Led7SegmentCharMap charMap;
(...)
public:
Led7SegmentCharMap(); // Konstruktor
uint8_t get7SegBitMap(const unsigned char outChar);
void LedMatrix::display(const String outString);
(...)
ledmatrix.cpp
#include <ledmatrix.hpp>
(...)
void LedMatrix::display(const String outString) {
(...) // get a char out of outString --> outChar
uint8_t charBitMap = charMap.get7SegBitMap(outChar); // get 7-seg-"bitmap"
(...)
};
(...)
My expection is that all dependencies are fulfilled (which is not true regarding the error messages). I had some trouble with initializing the bitMap-array. Maybe the undefined reference error is related to that?

Today I found a hint here: here.
With this I've got a compilable solution. In the cpp file it is necessary to move the bitMap declaration out of the constructor and do the initialization there. See new cpp file below.
So the initial question
How to get rid of "undefined reference to 'Class::member'"? in conjunction with initialization of an array
was wrong and should be:
How to declare an c-array in header file and define it in the cpp-file without specifying the size/dimension?
charmap7seg.hpp
class Led7SegmentCharMap {
public:
uint8_t get7SegBitMap(const unsigned char outChar);
private:
static const uint8_t bitMap[]; ///< Bitmap-Tabelle mit den Bitmustern
};
charmap7seg.cpp
const uint8_t Led7SegmentCharMap::bitMap[] = { ///< charMap contains bitmaps for 7-seg-displays
///< bzw. den Buchstaben darstellen.
0b0111111, ///< "0": Segmente f, e, d, c, b, a --> bitMap[0]
0b0000110, ///< "1": Segmente c, b --> bitMap[1]
0b1011011, ///< "2": Segmente g, e, d, b, a --> bitMap[2]
};
(...)

erase the uint8_t. you are redeclaring the bitmap and it's going out of scope when the constructor ends. instead do:
this->bitMap[] = { ///< charMap contains bitmaps for 7-seg-displays
//gfedcba
0b0111111, ///< "0": Segments f, e, d, c, b, a --> bitMap[0]
0b0000110, ///< "1": Segments c, b --> bitMap[1]
0b1011011, ///< "2": Segments g, e, d, b, a --> bitMap[2]
(...)
}

Related

C++ E0147 declaration is incompatible with static object

Websource.hpp
#ifndef WEBSOURCE_HPP
#define WEBSOURCE_HPP
#pragma once
class Colour
{
public:
unsigned char _ucRed;
unsigned char _ucGreen;
unsigned char _ucBlue;
Colour(unsigned char i_red, unsigned char i_green, unsigned char i_blue);
Colour(Colour& c);
Colour();
void setColour(unsigned char i_red, unsigned char i_green, unsigned char i_blue);
};
Colour::Colour(unsigned char i_red, unsigned char i_green, unsigned char i_blue)
{
this->setColour(i_red, i_green, i_blue);
}
Colour::Colour(Colour& c)
{
this->setColour(c._ucRed, c._ucGreen, c._ucBlue);
}
Colour::Colour()
{
this->setColour((unsigned char)0, (unsigned char)0, (unsigned char)0);
}
void Colour::setColour(unsigned char i_red, unsigned char i_green, unsigned char i_blue)
{
this->_ucRed = i_red;
this->_ucGreen = i_green;
this->_ucBlue = i_blue;
}
#endif
Website.hpp
#ifndef WEBSITE_HPP
#define WEBSITE_HPP
#pragma once
#include "Websource.hpp"
template <typename T, int N = 16>
class Page {
public:
static Colour c_logo; // logo colour
};
Colour website::Page<double>::Page::c_logo();
#endif
This code leads to Error 0147.
Severity Code Description Project File Line Suppression State Error
(active) E0147 declaration is incompatible with "Colour
website::Page::c_logo [with T=double, N=16]" (declared at line
31 of
"c:\Users\hasler\Documents\ga_design\Website.hpp") ga_design c:\Users\hasler\Documents\ga_design\Website.hpp 88
However, using another constructor works like a charm:
Colour website::Page<double>::Page::c_logo(0,0,0);
And I'm here struggling to understand why one constructor would work and another wouldn't.
To mark the question as answered: "It's a case of the most vexing parse in C++. Using Colour website::Page::Page::c_logo; will work." – R Sahu

running boost: lock free queues globally across multiple files

I would like to run a variant of example 46.3 from this website
http://theboostcpplibraries.com/boost.lockfree. I am on a linux system.
I would like to have the queue q be defined in a header file. I would like to have the produce and consume functions be in different files. So I would like to have global.h contain
static boost::lockfree::queue<int> q{100};
static std::atomic<int> sum{0};
void *produce (void*);
void *consume (void*);
I would then like to have a produce.cpp contain:
void *produce( void*)
{
for (int i = 1; i <= 10000; ++i)
q.push(i);
}
and I would like to have a consume.cpp contain
void *consume (void*)
{
int i;
while (q.pop(i))
sum += i;
}
I would then like to have my main.cpp contain
#include iosteam
#include iomanip
#include global
#include pthread
int main ()
{pthread_t t1;
pthread_t t2;
pthread_t t3;
int t1_iret;
t1_iret = pthread_create( &t1, NULL, produce, NULL);
if(t1_iret)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",t1_iret);
exit(EXIT_FAILURE);
}
int t2_iret;
t2_iret = pthread_create( &t2, NULL, consume, NULL);
if(t2_iret)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",t2_iret);
exit(EXIT_FAILURE);
}
int t3_iret;
t3_iret = pthread_create( &t3, NULL, consume, NULL);
if(t3_iret)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",t3_iret);
exit(EXIT_FAILURE);
}
pthread_join( t1, NULL);
pthread_join( t2, NULL);
pthread_join( t3, NULL);
return 0; }
Additionally, I was wondering if it would be possible to do what I have described with strings rather then integers.
edit1: when I try and make the queue be queue of strings I get::
/usr/local/include/boost/lockfree/queue.hpp: In instantiation of ‘class boost::l ockfree::queue >’:
/home/ubuntu/Project/src/main.cpp:15:37: required from here
/usr/local/include/boost/lockfree/queue.hpp:87:5: error: static assertion failed : (boost::has_trivial_destructor::value)
BOOST_STATIC_ASSERT((boost::has_trivial_destructor::value));
^
/usr/local/include/boost/lockfree/queue.hpp:91:5: error: static assertion failed : (boost::has_trivial_assign::value)
BOOST_STATIC_ASSERT((boost::has_trivial_assign::value));
^
In file included from /usr/local/include/boost/lockfree/queue.hpp:21:0,
from /home/ubuntu/Project/src/main.cpp:5:
/usr/local/include/boost/lockfree/detail/copy_payload.hpp: In instantiation of ‘ static void boost::lockfree::detail::copy_constructible_and_copyable::copy(T&, U &) [with T = std::basic_string; U = int]’:
/usr/local/include/boost/lockfree/detail/copy_payload.hpp:49:25: required from ‘void boost::lockfree::detail::copy_payload(T&, U&) [with T = std::basic_string ; U = int]’
/usr/local/include/boost/lockfree/queue.hpp:402:61: required from ‘bool boost: :lockfree::queue::pop(U&) [with U = int; T = std::basic_string; A0 = boost::parameter::void_; A1 = boost::parameter::void_; A2 = boost::par ameter::void_]’
/home/ubuntu/Project/src/main.cpp:21:24: required from here
/usr/local/include/boost/lockfree/detail/copy_payload.hpp:38:11: error: invalid cast from type ‘std::basic_string’ to type ‘int’
u = U(t);
You need to declare, but not define, your variables in global.h:
extern boost::lockfree::queue<int> q;
extern std::atomic<int> sum;
Then you need to define them in a separate file, global.cpp:
boost::lockfree::queue<int> q{100};
std::atomic<int> sum{0};
I think this should fix your issue. For details, see How do I use extern to share variables between source files?
As for the second part, asking why you can't make a lock-free queue of strings, well, that is answered by the error message: has_trivial_destructor is false for std::string, because it's a dynamically-sized string which allocates memory. You won't be able to use it in this sort of lock-free queue. You can try using a fixed-size string class instead, or std::array<char, N>.

exposing a function with 2D slice as a parameter in a c-shared library (to be used in Java via JNA and C)

I am trying to write a simple matrix operations API using go and expose the APIs as a shared library. This shared library will be used from Java(using JNA) and from C.
The documentation is very sparse about using any data type beyond simple int or string as function parameters.
My requirement is to expose functions with 1 or more 2D slices as parameters AND also as return types. I am not able to figure out if such a thing is supported.
Is this possible? Are there any examples for this?
I think the key point is to have a look to the c bindings of slice,string and int generated by go build tool. I not tried 2D slice, but it should no different to 1D slice with unsafe pointer converter, maybe just be one more time allocation and convertion.
I'm not sure it's the best way, but here's the example for 1D slice:
the go part:
import "C"
//export CFoo
func CFoo(content []byte) string{
var ret []byte
//blablabla to get ret
cbuf := unsafe.Pointer(C.malloc(C.size_t(len(ret))))
C.memcpy(cbuf, unsafe.Pointer(&ret[0]), C.size_t(len(ret)))
var finalString string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&finalString))
hdr.Data = uintptr(unsafe.Pointer(cbuf))
hdr.Len = len(ret)
return finalString
}
compile with -buildmode=c-shared, to get libmygo.so.
I not know JNA, expecting it like JNI. the JNI part as well as pure C part:
#include <stdio.h>
#include <jni.h>
#include <string.h>
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt32 GoInt;
typedef GoUint32 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
JNIEXPORT JNICALL jbyteArray Java_com_mynextev_infotainment_app_myev_Native_foo(JNIEnv* env, jobject obj,jbyteArray content){
JNIEnv ienv = *env;
void * Ccontent = ienv->GetByteArrayElements(env, content, 0);
int Lcontent = ienv->GetArrayLength(env, content);
GoSlice Gcontent = {Ccontent, Lcontent, Lcontent};
if(!gret.n){
printf("jni CDoAESEnc");
return NULL;
}
jbyteArray ret = ienv->NewByteArray(env, gret.n);
ienv->SetByteArrayRegion(env, ret, 0, gret.n, gret.p);
free((void*)gret.p);
ienv->ReleaseByteArrayElements(env, content, Ccontent, JNI_ABORT);
return ret;
}
build it with libmygo.so.
finally you get two so files. one for C which can be used standalone; one for Java which must be used with libmygo.so together.

Strict aliasing rule in C++11

I use the following C structs in my C++11 code (the code comes from liblwgeom of PostGis, but this is not the core of the question). The code is compiled with the following options using g++-4.8:
-std=c++11 -Wall -Wextra -pedantic-errors -pedantic -Werror
and I don't get any errors during compilation (or warnings) (should I get any?)
Question
Is safe to use LWPOLY (actually pointed by LWGEOM*) in functions that accept LWGEOM and don't modify the void *data; member. I understand that this is poor man's inheritance but this is what I need to work with.
Details
POLYGON:
typedef struct
{
uint8_t type; /* POLYGONTYPE */
uint8_t flags;
GBOX *bbox;
int32_t srid;
int nrings; /* how many rings we are currently storing */
int maxrings; /* how many rings we have space for in **rings */
POINTARRAY **rings; /* list of rings (list of points) */
}
LWPOLY; /* "light-weight polygon" */
LWGEOM:
typedef struct
{
uint8_t type;
uint8_t flags;
GBOX *bbox;
int32_t srid;
void *data;
}
LWGEOM;
POINTARRAY:
typedef struct
{
/* Array of POINT 2D, 3D or 4D, possibly missaligned. */
uint8_t *serialized_pointlist;
/* Use FLAGS_* macros to handle */
uint8_t flags;
int npoints; /* how many points we are currently storing */
int maxpoints; /* how many points we have space for in serialized_pointlist */
}
POINTARRAY;
GBOX:
typedef struct
{
uint8_t flags;
double xmin;
double xmax;
double ymin;
double ymax;
double zmin;
double zmax;
double mmin;
double mmax;
} GBOX;
Am I violating strict aliasing rule when I do something like?
const LWGEOM* lwgeom;
...
const LWPOLY* lwpoly = reinterpret_cast<const LWPOLY*>(lwgeom);
I know that in PostGis types are specifically designed to be "compatible" however I'd like to know if I am violating the standard by doing so.
Also, I noticed that PostGis is not compiled with strict aliasing disabled by default (at least version 2.1.5).
Solution
My colleague helped me to investigate it and it seems the answer is No it doesn't violate strict aliasing, but only in case we access LWGEOMS members that are of the same type as of LWPOLY's and are laid out in the beginning of the struct contiguously. Here is why (quoting standard):
3.10.10 says that you can access a member through a pointer to "aggregate or union".
8.5.1 defines aggregates (C structs are aggregates):
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or
protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
9.2.19 says that pointer to the struct is the same as pointer to the fist member for standard layout classes (C structs are standard layout).
Whether this is a safe way to code is a different question.
Yes, it violates the strict aliasing rule. LWGEOM and LWPOLY are unrelated types, and so are int and void*. So, for example, modification to lwgeom->data may not be read through lwpoly->nrings and vice versa.
I validated this with GCC4.9. My code is as follows:
#include <cinttypes>
#include <iostream>
using namespace std;
typedef struct {
uint8_t type; /* POLYGONTYPE */
uint8_t flags;
int32_t srid;
int nrings; /* how many rings we are currently storing */
} LWPOLY; /* "light-weight polygon" */
typedef struct {
uint8_t type;
uint8_t flags;
int32_t srid;
void *data;
} LWGEOM;
void f(LWGEOM* pgeom, LWPOLY* ppoly) {
ppoly->nrings = 7;
pgeom->data = 0;
std::cout << ppoly->nrings << '\n';
}
int main() {
LWGEOM geom = {};
LWGEOM* pgeom = &geom;
LWPOLY* ppoly = (LWPOLY*)pgeom;
f(pgeom, ppoly);
}
Guess what, the output is 7.

OpenCL & Xcode - Incorrect kernel header being generated for custom data type argument

I'm parallelising a LBM using OpenCL and have across a problem regarding how the kernel header files are being generated for a custom data type as an argument to the kernel. I define the data type within the kernel file (rebound.cl) as required (typedef struct {...} t_speed;) and the data type t_speed is generated in the header file which is obviously syntactically incorrect and the build subsequently fails. Whilst this is more of an annoyance than a major problem, fixing it would save a lot of time!
Kernel file: rebound.cl
#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#elif defined(cl_amd_fp64)
#pragma OPENCL EXTENSION cl_amd_fp64 : enable
#else
#error "Double precision floating point not supported by OpenCL implementation."
#endif
#define NSPEEDS 5
typedef struct {
double speeds[NSPEEDS];
} t_speed;
__kernel void rebound (__global t_speed* cells,
__global t_speed* tmp_cells,
__global const unsigned char* obstacles,
const unsigned short int count)
{
int i = get_global_id(0);
if (i < count) {
if (obstacles[i]) {
cells[i].speeds[1] = tmp_cells[i].speeds[3]; /* East -> West */
cells[i].speeds[3] = tmp_cells[i].speeds[1]; /* West -> East*/
cells[i].speeds[2] = tmp_cells[i].speeds[4]; /* North -> South */
cells[i].speeds[4] = tmp_cells[i].speeds[2]; /* South -> North */
}
}
}
Kernel header file: rebound.cl.h
/***** GCL Generated File *********************/
/* Automatically generated file, do not edit! */
/**********************************************/
#include <OpenCL/opencl.h>
typedef struct {
double [5] speeds;
} _t_speed_unalign;
typedef _t_speed_unalign __attribute__ ((aligned(8))) t_speed;
extern void (^rebound_kernel)(const cl_ndrange *ndrange, t_speed* cells, t_speed* tmp_cells, cl_uchar* obstacles, cl_ushort count);

Resources