|
|
I am writing code for an ARM processor and compiling with GCC inside Eclipse IDE. When the application wants something to get done, it needs to create a task and queue it:
typedef uint32_t (*task_t)(uint8_t* data, uint16_t dataSizeBytes);
void queueTask(task_t task, uint8_t* data, uint16_t dataSizeBytes); Now I want to be able to queue C++ tasks inside the same task queue:
#include <functional>
using namespace std;
using taskCpp_t = function <uint32_t(uint8_t* dataPtr, uint16_t dataSizeBytes)>;
void queueTaskCpp(taskCpp_t task, uint8_t* data, uint16_t dataSizeBytes); The compiler complains when I simply try to cast my C++ function pointer into a C function pointer:
void queueTaskCpp(taskCpp_t task, uint8_t* data, uint16_t dataSizeBytes) {
queueTask((task_t)task, NULL, 0); } Does anybody know what I can do to be able to queue taskCpp_t tasks into the same queue as the task_t are queued into?
|
|
|
|
|
I don't think you can. A C++ object cannot be used as a simple pointer as the two are totally different.
|
|
|
|
|
You may use a C++ static function as task. That would be equivalent to a standard C function.
|
|
|
|
|
I'm hoping to be able to use the function like this:
queueTaskCpp([](uint8_t* data, uint16_t dataSizeBytes) {
}, NULL, 0); I would assume the above function implementation would become static, right? God forbid if the function gets implemented on the stack, obviously that would mean I can't use this concept at all since the function implementation on the stack will most likely be corrupt when it's time to execute the queued function. I'm not planning to use any classes or object orientedness, I'm only using C++ to be able to pass anonymous functions like this.
|
|
|
|
|
To show how different the two things are try this:
int main ()
{
taskCpp_t t;
cout << "taskCpp_t size: " << sizeof (taskCpp_t) << '\n';
cout << "task_t size: " << sizeof (task_t) << '\n';
}
I get:
taskCpp_t size: 64
task_t size: 8
but it is up the compiler what a function object should contain.
Mircea
|
|
|
|
|
write an 8051 embedded c program in which after every 200 ms the leds connected to port 2 are turned on or off. assume xtal 11.0592mhz. use timer 0 in mode 1.
|
|
|
|
|
I can't be bothered. You do it.
|
|
|
|
|
|
Start reading the 8051 datasheet (that you may find easily online) and your C compiler documentation (because you probably have to implement the timer 0 interrupt servicing routine).
|
|
|
|
|
It seems to be a good idea. Good luck!
|
|
|
|
|
|
I feel I'm turning slightly mad. In my mind the two variants below should give the same output:
class A {
public:
A () { cout << "A created" << endl; }
};
class B {
public:
B () { cout << "Default B constructor" << endl; }
B (A oa) { cout << "B created from A" << endl; }
B (const B& other) { cout << "B copy constructor" << endl; }
};
int main()
{
A aobj;
B* bptr = new B (B (aobj));
cout << "--------" << endl;
B bobj (aobj);
B* bbptr = new B (bobj);
}
After A is created, I create a B from A and then I copy the B using the copy constructor. At least that's my intention.
However the output I get is:
A created
B created from A
--------
B created from A
B copy constructor
What am I missing here?
Mircea
|
|
|
|
|
I might be wrong, but
B (aobj) from
new B (B (aobj)) should call move constructor, not copy constructor ...
P.S.
B (B (aobj)) would call a copy constructor only if what is inside of first brackets would be an already created B object, a l value, so, since
B (aobj) is an anonymous object, move construct would be called.
P.P.S. I added move constructor to B
B(B&& rhs) { std::cout << "B move constructor" << std::endl; }
and is never called either.
modified 23-Sep-20 6:34am.
|
|
|
|
|
The standard says that a move constructor is generated by default only for classes that don'
t have a copy constructor. Otherwise the copy constructor is invoked. It has to be like that for compatibility reasons: move constructors were introduced only in C++11.
As you did, I've also tried adding the move constructor with the same results
Mircea
|
|
|
|
|
I stepped through that code with the debugger, and it appears that it treats new B (B (aobj)); the same as new B (aobj); . That is to say, it optimises out the creation of the interim object, as it is never needed.
|
|
|
|
|
I was also ready to blame the compiler except that I was using the code in debug mode with all optimizations turned off. You can try it even with something like i=1;i=2; and you will see that it is generating not optimized code.
Besides, my code is abstracted from a real world program where the copy constructor was making a deep copy of an object full of pointers and memory allocations. I cannot see the compiler simply throwing away all those side-effects.
Also I tried with both VisualStudio and g++ and both compilers behave the same way. It must be something deeper in this than a compiler bug.
As I use to say in these cases: the silly is on the other side of the screen
Mircea
|
|
|
|
|
A more thorough use of Google brought me the this:
Quote: Whenever a temporary object is created for the sole purpose of being copied and subsequently destroyed, the compiler is allowed to remove the temporary object entirely and construct the result directly in the recipient (i.e. directly in the object that is supposed to receive the copy).
This process is called elision of copy operation. It is described in [class.copy.elison] in the language standard.
In this case
B* bptr = new B(B(aobj));
can be transformed into
B* bptr = new B(aboj);
even if the copy constructor has side-effects.
Mircea
|
|
|
|
|
|
I'm somewhat impressed by this compiler, but the compiler is allowed to means that it could behave differently under different compilers, especially if the construction of the temporary object has side effects.
|
|
|
|
|
On the contrary: I'm quite unimpressed ("we are not amused").
You know what they say that C makes it easy to shoot yourself in the foot and C++ gives you a bazooka. In this case I's say you walk with hand grenades in your pocket; safety pins are optional.
Note that even in the variant that 'works':
B bobj (aobj);
B* bbptr = new B (bobj);
bobj is susceptible to being optimized out of existence and turned back into the previous case.
To leave it to the compiler, or the compiler designer, if a function should be called or not, and to do it without even a warning, is unconscionable. Haven't researched the history of this section of the standard but I'd dare say that it dates back to the '03 time and the 'efficiency wars'. That was put to rest with the '11 move constructors and assignment operators but probably that section of the standard slipped through.
In fairness, I should say that it's not something that happens too often. This is the first time I run into the issue but I'll keep it in mind for the future.
Mircea
|
|
|
|
|
Yes. I'm very unimpressed by the spec but still impressed that the compiler bothered to implement this "optimization".
|
|
|
|
|
What compilers (and linkers) do you use to compile pure assembler code/files? On Microsoft website MASM has Visual Studio 2005 as prerequisite.
|
|
|
|
|
|
You may want to check out NASM[^]
|
|
|
|