Call to class method expects more arguments than I'm providing

Hi - This has me stumped. I am writing a wrapper class around the MCP_CAN lib for my own uses.

The issue I am having is with the MCP_CAN class method readMsgBuf - the Arduino IDE error message says its expecting 4 arguments but getting 3.

Why is it giving me an error complaining about not passing the 4th argument?

sketch/LayoutCan.cpp: In member function 'void LayoutCan::ReadCan()':
LayoutCan.cpp:67:45: error: no matching function for call to 'MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte (*)[8])'
   _mcpCan->readMsgBuf(&_rxId, &_len, &_rxBuf);      // Read data: len = data length, buf = data byte(s)
                                             ^
In file included from sketch/LayoutCan.h:8:0,
                 from sketch/LayoutCan.cpp:5:
/Users/brantwinter/Documents/Arduino/libraries/MCP_CAN_lib/mcp_can.h:116:11: note: candidate: byte MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte*, byte*)
     INT8U readMsgBuf(INT32U *id, INT8U *ext, INT8U *len, INT8U *buf);   // Read message from receive buffer
           ^
/Users/brantwinter/Documents/Arduino/libraries/MCP_CAN_lib/mcp_can.h:116:11: note:   candidate expects 4 arguments, 3 provided
/Users/brantwinter/Documents/Arduino/libraries/MCP_CAN_lib/mcp_can.h:117:11: note: candidate: byte MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte*)
     INT8U readMsgBuf(INT32U *id, INT8U *len, INT8U *buf);               // Read message from receive buffer
           ^
/Users/brantwinter/Documents/Arduino/libraries/MCP_CAN_lib/mcp_can.h:117:11: note:   no known conversion for argument 3 from 'byte (*)[8] {aka unsigned char (*)[8]}' to 'byte* {aka unsigned char*}'
exit status 1
no matching function for call to 'MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte (*)[8])'

I have looked at the MCP_CAN library header file and note that it does indeed take 3 arguments:

INT8U readMsgBuf(INT32U *id, INT8U *ext, INT8U *len, INT8U *buf);   // Read message from receive buffer
INT8U readMsgBuf(INT32U *id, INT8U *len, INT8U *buf);               // Read message from receive buffer

The following are my trimmed down class header and source code files from my own class I am writing. I declare a pointer to an MCP_CAN object for later use.

Header file:

class LayoutCan
{
  private:
    MCP_CAN *_mcpCan;
    char _msgString[128]; // Array to store serial string   
    long unsigned int _rxId;
    byte _len;
    byte _rxBuf[8];

  public:
    LayoutCan(byte canPin, byte srcUseHardCodedId, byte srcId);
    void begin();
    void ReadCan();

Source code file:

#include "LayoutCan.h"

LayoutCan::LayoutCan(byte canPin, byte srcUseHardCodedId, byte srcId)
  : _canPin(canPin), _srcUseHardCodedId(srcUseHardCodedId), _srcId(srcId) {}

void LayoutCan::begin() {
  _mcpCan = new MCP_CAN(_canPin);
  
  SPI.setClockDivider(SPI_CLOCK_DIV2);         // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz)
  
  //init CAN0 bus, baudrate: 250k@16MHz
  if(_mcpCan->begin(MCP_ANY, CAN_250KBPS, MCP_16MHZ) == CAN_OK){
    Serial << "CAN PIN " << _canPin << " Init OK!\r\n";
    _mcpCan->setMode(MCP_NORMAL);
  } else Serial << "CAN PIN " << _canPin << " Init Fail!!!\r\n";
}

void LayoutCan::ReadCan() {
  _mcpCan->readMsgBuf(&_rxId, &_len, &_rxBuf);      // Read data: len = data length, buf = data byte(s)
    
  if((_rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
    sprintf(_msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (_rxId & 0x1FFFFFFF), _len);
  else
    sprintf(_msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", _rxId, _len);

  Serial.print(_msgString);
  
  if((_rxId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(_msgString, " REMOTE REQUEST FRAME");
      Serial.print(_msgString);
  } else {
    for(byte i = 0; i<_len; i++){
      sprintf(_msgString, " 0x%.2X", _rxBuf[i]);
      Serial.print(_msgString);
    }
  }
        
  Serial.println();
}

It's expecting a pointer to a buffer. You're trying to add another level of indirection:

   _mcpCan->readMsgBuf(&_rxId, &_len, &_rxBuf);

_rxBuf is already an array, no need for the ampersand. Try this instead

   _mcpCan->readMsgBuf(&_rxId, &_len, _rxBuf);

The has 2 overloaded functions like this

 INT8U readMsgBuf(INT32U *id, INT8U *ext, INT8U *len, INT8U *buf);   // Read message from receive buffer
 INT8U readMsgBuf(INT32U *id, INT8U *len, INT8U *buf);               // Read message from receive buffer

One takes 3 arguments and the other takes 4 but you need to make sure that the data types you are using match the appropriate function signature.

wildbill:
It's expecting a pointer to a buffer. You're trying to add another level of indirection:

   _mcpCan->readMsgBuf(&_rxId, &_len, &_rxBuf);

_rxBuf is already an array, no need for the ampersand. Try this instead

   _mcpCan->readMsgBuf(&_rxId, &_len, _rxBuf);

Ok that worked. I am still confused as to why. I'll have to do some more homework on pointers.

Does it help to know that _rxBuf is shorthand for &_rxBuf[0] ?

UKHeliBob:
The has 2 overloaded functions like this

 INT8U readMsgBuf(INT32U *id, INT8U *ext, INT8U *len, INT8U *buf);   // Read message from receive buffer

INT8U readMsgBuf(INT32U *id, INT8U *len, INT8U *buf);              // Read message from receive buffer



One takes 3 arguments and the other takes 4 but you need to make sure that the data types you are using match the appropriate function signature.

This was indeed the issue.

I am confused by this: the 3rd argument of the 2nd readMsgBuf method is INT8U *buf. Does this mean it takes a pointer to a byte object?

The & that I removed is a de-referencer (for want of a better term). So by removing the & from my _rfBuf I am passing the pointer to the method - correct? Why do I need the & on the INT32U *id, INT8U *len arguments if they too are already pointers?

wildbill:
Does it help to know that _rxBuf is shorthand for &_rxBuf[0] ?

oh.... now I'm really confused!

_rxBuf is just the start address of the array.

_rxBuf[0] is get the first item (=value) from that that array

&_rxBuf[0] is get the address of the first item of that array. Which is stored at the start of the array hence it has the same address :wink: