I used static member in class and reference to assembly, in sperate files I got error, Is there anyway to solve it?

the original file is like
OkTest.ino (856 位元組)

#include "arduino.h"

class MyClass {

    public:
        MyClass();
        ~MyClass();
        void setVariable(int);
        static int MyVariable;
};

int __attribute__((used)) MyClass::MyVariable __asm__("MyVariable");

MyClass::MyClass(){
    MyVariable = 0;
};
MyClass::~MyClass(){
};

void MyClass::setVariable(int input){
    register uint8_t tmp;
    __asm__ __volatile__(
        "mov %0, %A1\n\t" \
        "sts MyVariable, %0 \n\t" \
        "mov %0, %B1\n\t" \
        "sts MyVariable+1, %0\n\t" \
        :
        :"r" (tmp), "r" (input) 
        :
    );
};

MyClass check;

void setup() {
    Serial.begin(9600);
    Serial.print("check before setVariable = "); Serial.println(check.MyVariable);
    check.setVariable(1000);
    Serial.print("check variable MyClass.MyVariable = "); Serial.println(check.MyVariable);
}
void loop() {
}

It works fine...

but when I separate them into individually file like this
ErrorTest.ino (283 位元組)

#include "MyClass.h"

void setup() {
    Serial.begin(9600);
    Serial.print("check before setVariable = "); Serial.println(check.MyVariable);
    check.setVariable(1000);
    Serial.print("check variable MyClass.MyVariable = "); Serial.println(check.MyVariable);}

void loop() {
}

MyClass.cpp (458 位元組)

#include "MyClass.h"

int __attribute__((used)) MyClass::MyVariable __asm__("MyVariable");

MyClass::MyClass(){
    MyVariable = 0;
};
MyClass::~MyClass(){
};

void MyClass::setVariable(int input){
    register uint8_t tmp;
    __asm__ __volatile__(
        "mov %0, %A1\n\t" \
        "sts MyVariable, %0 \n\t" \
        "mov %0, %B1\n\t" \
        "sts MyVariable+1, %0\n\t" \
        :
        :"r" (tmp), "r" (input) 
        :
    );
};

MyClass check;

MyClass.h (237 位元組)

#ifndef MyClass_H
#define MyClass_H
#include "arduino.h"

class MyClass {

    public:
        MyClass();
        ~MyClass();
        void setVariable(int);
        static int MyVariable;
};


extern MyClass check;    
    
#endif
     

then I got the error message
Arduino: 1.8.13 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"
C:\Users\Tracker\AppData\Local\Temp\cckoPtOv.ltrans0.ltrans.o: In function setup': D:\Working\ErrorTest/ErrorTest.ino:5: undefined reference to MyClass::MyVariable'

D:\Working\ErrorTest/ErrorTest.ino:5: undefined reference to `MyClass::MyVariable'

D:\Working\ErrorTest/ErrorTest.ino:7: undefined reference to `MyClass::MyVariable'

D:\Working\ErrorTest/ErrorTest.ino:7: undefined reference to `MyClass::MyVariable'

collect2.exe: error: ld returned 1 exit status

exit status 1

Error compiling for board Arduino Nano.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Thanks for your recommendation~
but it comes new error message
redefinition of 'int MyClass::MyVariable'
or what you mean is to leave this static member in global environment?

and I found that , the public member can be private or protected, if assign as public, it will be error as I try to.
new I have two way to do,

  1. put static member to private, and add function call in public to access that static member
  2. put static member to private, then add a variable pointer in public, in this case main program can access the static member in data pointer way..
    I just wandering is anyway to keep static member public in sperate file?

check something like this

if you want to use assembly it's more tricky, you'll probably have to keep a handle to the address of the class variable to be able to refer to it

1 Like

thanks for your point, I see, it's work for this program without reference to assembly ~
(and I misunderstanding that the static member can be public, and I find once I label it in assembly, the error occur, )
Is that possible pass MyVariable to assembly in MyClass::setVariable() like use asm("lds %0, MyVariable\n\t" "::"r" (tmp1):slight_smile: ?
because original I write assembly is for optimizing code purpose.. thanks

The assembly will struggle to find the variable you are referring to as its name is mangled by the C++ compiler

It would be easier if you had a global variable - I’m not sure what’s the purpose of the class there or the assembly language

1 Like

Thank you for your kindly help, the reason way to use individual file with class in assembly is because to optimize the performance and also keep program reusable, thanks for all your help, so far I'm using data pointer to do this, and work fine.. I put those file here in case someone needs it.
at least It's one solution
and maybe later we can find out better way to solve it .

thanks again.. to eveyone who helps me... :slight_smile:

the example files that I currently used, list as following...

ErrorTest.ino

#include "MyClass.h"

void setup() {
    Serial.begin(115200);
    Serial.print("check before setVariable = "); Serial.println(*check._MyVariable);
    check.setVariable(1000);
    Serial.print("check variable MyClass.MyVariable = "); Serial.println(*check._MyVariable);}

void loop() {
}

MyClass.h

#ifndef MyClass_H
#define MyClass_H
#include "arduino.h"

class MyClass {

    public:
        MyClass();
        ~MyClass();
        void setVariable(int);
        int *_MyVariable;
    private:
        static int  MyVariable;
};


extern MyClass check;    
    
#endif
     

MyClass.cpp

#include "MyClass.h"

int __attribute__((used)) MyClass::MyVariable __asm__("MyVariable");

MyClass::MyClass(){
    MyVariable = 0;
    _MyVariable = &MyVariable;
};
MyClass::~MyClass(){
};

void MyClass::setVariable(int input){

    register uint8_t tmp;
    __asm__ __volatile__(
        "mov %0, %A1\n\t" \
        "sts MyVariable, %0 \n\t" \
        "mov %0, %B1\n\t" \
        "sts MyVariable+1, %0\n\t" \
        ::"r" (tmp), "r" (input) :
    );
};

MyClass check;

Assembly is not really portable nor reusable easily and the compiler / optimizer will usually generate better code than you for most tasks…

1 Like

Thank you!

thank you,

finally I try this as temporary solution, please take a look
(of cause it's not only a way allow me to do next job)

allow me explain the whole issue post by my poor English... :slight_smile:

in the beginning I define a class with some function using public variable in assembler, the way I used variable in assembly is directly reference to label in assembly domain (global) like

`int attribute((used)) MyVariable asm("MyVariable");

so that I can access in assembly like this

`asm ("lds %0 MyVariable")

in this way I can optimize performance better, so it must be static, and also needs to be access at main program as public

when I put those class with main program together in one file (OK.ino) it works very will, then I try to sperate then into three files, (just put one certain function at two file (cpp and h) without disturb main program, and also easy to maintain and read), the error comes

please see the original post in the top ErrorTest.ino and MyClass.cpp MyClass.h

It looks like the compiler not allow the variable be access by program in outside file, (the variable has defined as static , public , and labeling in assembly (global))

if I do not labeling in assembly (global area), then the external program can access then, but assembly will not be able to access, and comes MyVariable not defined message,

then I can use different way to make inline assembly transfer parameter in, like this

` asm("ld %0, %A[MyVariable]\n\t" "ld %1, %B[MyVariable]\n\t" :: "r" (tmp1), "r" (tmp2), [MyVariable] "+r" (MyVariable) : )

but it takes CPU time for me in my case, and also I found other issue in this way, it look like MyVariable will be changed by other issue (I don't know why, I will not discuss this issue here, it become more complicated)

so finally I use public data pointer to access static private variable, and it work fine,
It's not a good solution, and I don't know why the original issue happen, but
now I can go forward.. it just fine
that is all about this post..

thanks for your kindly help. It's great for me,

Identifiers have two properties that you need to explore ➜ scope and linkage.

Scope is where an identifier is visible.
Linkage is a way of making different declarations of an identifier refer to the same object. There are three types of linkage: external, internal, and none.

If an identifier has internal linkage, it is not linked with identifiers in other translation units, so it's not accessible.

If an identifier has external linkage, it can be accessed in another translation unit by declaring an identifier with the same name and also with external linkage. When the codes are linked together, identifiers with external linkage are resolved by the linker so that they refer to the same storage. I suspect that's what you need for your assembly code.


that being said, I still don't get the idea of

this is usually not true nowadays. Compliers and optimisers have ways to look at your code that you don't suspect :slight_smile:

nor the idea of having a class and a class variable... Why don't you just use a global variable that is not restricted to a specific class anyway ?

the whole thing feels like an XY problem to me.

thank you, I will look at that, I am just newbie, it's lot more thing to learn about, thank you again~
by the way, I just try that out, and guess what, It works, only I need to do is to name the variable in different name for assembly, so that it will not be the same name as public member, thank you~
20240121 update, my mistake, the problem still, I will find another way to do...
thanks ....

Why do you need to go to assembly level?

combine IO control directly in byte not in bit, it's take a better performance..
and others ..
original I used C it takes 100uS only only doing thing , then in assembly do I/O Time period stuff together, it takes only 10uS, it's very good for me in real time small system programming..

If you need indeed close time control on what’s going on then indeed it might be useful

It `s very unusual. As a rule, if the use of assembler gives an advantage, it is by percentage, and not by several times.
Could you give a comparative example of C code and assembly code?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.