0

I am writing some code for the Arduino IDE and running into an issue where a reference, that is a class member, seems to lose/change its value across function calls.

MyStream is defined as an extern in MyStream.cpp and inherits from Stream.

In code below, the references seem to be equal in the constructor but not in foo()! Can't figure out what's going on

StreamProvider.h

class StreamProvider {
  private:
    Stream& stream;
  public:
    StreamProvider(Stream&);
    size_t foo(const char*);
};

StreamProvider.cpp

StreamProvider::StreamProvider(Stream& s)
  : stream(s)
{
  Serial.printf("\nMyStream %x", &MyStream);
  Serial.printf("\nStream %x", &stream);
}

size_t StreamProvider::foo(const char* buf) {

  Serial.printf("\nMyStream %x", &MyStream);
  Serial.printf("\nStream %x", &stream);
}

MyStream.h

class _MyStream: public Stream {
     size_t write(uint8_t);
     int available();
     int read();
     int peek();
};

extern _MyStream MyStream;

MyStream.cpp

size_t _MyStream::write(uint8_t) {
  return 0;
}
int _MyStream::available() {
  return 0;
}
int _MyStream::read() {
  return 0;
}
int _MyStream::peek() {
  return 0;
}
_MyStream MyStream;

Output

MyStream 3ffee340       /** ctor**/
Stream 3ffee340         /** ctor**/
MyStream 3ffee340       /** foo**/
Stream 3fffff6c ???     /** foo**/

I have tried to look around and this seems unexplainable! Of course nothing is, but then I am not sure if I am missing something here...Any help is appreciated.

Thanks

  • 3
    Please provide a [mcve] – 463035818_is_not_an_ai Apr 17 '20 at 13:17
  • 3
    Unfortunately, your snippets of code aren't connected in a way that allows anyone to reproduce your problem. Invest some effort to producing a [mcve] and someone may have a fighting chance of offering help - which they don't at present. – Peter Apr 17 '20 at 13:21
  • The bug can be anywhere in your code. Some bug, somewhere in your code could, for example, be corrupting memory and clobbering the reference pointer in this object. I'm sure you understand why the lack of [mre] makes it logically impossible for anyone to give you the answer here. Welcome to C++! – Sam Varshavchik Apr 17 '20 at 13:24
  • Your `foo` function fails to return a value when you're supposed to return a `size_t`. Thus undefined behavior if you're calling this function. I am not familiar with the `Serial.printf` function, but the undefined behavior could affect your output, even if the actual (wrong) return is done after the call to `Serial.printf`. – PaulMcKenzie Apr 17 '20 at 13:35
  • The code has externs all over and class inter dependency so i've uploaded the code here. https://github.com/girishsarwal/ref-init-issue platform is NodeMCU. – girishsarwal Apr 17 '20 at 13:42
  • Well, like I mentioned, your code has undefined behavior. There is no return for a function declared as returning a value. – PaulMcKenzie Apr 17 '20 at 13:46
  • I just found another behavior, if ```StreamProvider(Stream&);``` is changed to take two arguments like so, ```StreamProvider(String&, Stream&)```, it works! the references point to the same object (verified by hex address as earlier)... could this be a compiler optimization thingy? – girishsarwal Apr 17 '20 at 13:47
  • Why not fix what I suggested first. Your code's behavior could be anything until you address that issue of a non-return from a function that is declared to return a value. – PaulMcKenzie Apr 17 '20 at 13:47
  • To convince that not returning a value has an effect, [look at this](http://coliru.stacked-crooked.com/a/f3e73fdd3c6b33b9). Then [look at this](http://coliru.stacked-crooked.com/a/d9a170ec8aed6a62). Adding the `return 1;` statement caused the output to finally display, while the bugged version with the commented-out `return 1;` seg faults. That's why you can't conclude anything until you fix that error. – PaulMcKenzie Apr 17 '20 at 13:54
  • @PaulMcKenzie done that. no luck. not sure why that should affect. The member variable is being initialized in the ctor and should persist a value regardless of the return type of a member function, that's the purpose of having member variables no? Calling convention is stdcall here so i don't see the caller being able to mess with the stack either. – girishsarwal Apr 17 '20 at 13:56
  • 1
    Did you not see the example? It could have a huge effect. Undefined behavior means just that --undefined. Don't presume what undefined behavior will do. [See this](https://stackoverflow.com/questions/9936011/if-a-function-returns-no-value-with-a-valid-return-type-is-it-okay-to-for-the) – PaulMcKenzie Apr 17 '20 at 13:58
  • Yups i saw the example and totally see what you're saying; convinced on that. However, changing the return type of foo to void makes no difference. the foo is infact a write function which is why the size_t. I know I maybe asking for too much here but replicating from the github source code will reveal what I'm facing. Could I request you to have a look at the GH repo. thanks – girishsarwal Apr 17 '20 at 14:05

1 Answers1

0

I just encountered a similar problem. I ended up changing the opimization level of the compiler to -O2 from the default (I think is -O3). That fixed my problem.

  • This does not answer OP's question. An advice to fix a problem by replacing a standard option with another one is no solution. – zkoza Mar 29 '21 at 21:37