-3

The code below has three arguments of the type double*. The code is part of an Arduino PID library and the user would typically give a reading of an analogue port or some kind of sensor as the argument for the "input" term and some fixed value or user controlled variable as the value of the "setpoint" term. But the argument is of type double*. Shouldn't the user get an error when he provides a double?

PID::PID(double* Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{
    myOutput = Output;
    myInput = Input;
    mySetpoint = Setpoint;
    inAuto = false;

    PID::SetOutputLimits(0, 255); // default output limit corresponds to 
                                  // the arduino pwm limits

    SampleTime = 100;             // default Controller Sample Time is 0.1 seconds

    PID::SetControllerDirection(ControllerDirection);
    PID::SetTunings(Kp, Ki, Kd);

    lastTime = millis()-SampleTime;
}

Does the constructor just take the address of the double that the user provides?

If the user was reading some temperature data, say double temp=AnalogRead(1). So reading whatever comes in from the analogue pin 1, would myOutput just be the address of those incoming temperature readings?

myInput, myOutput and mySetpoint get de-referenced in another member function.

double input = *myInput;
double error = *mySetpoint - input;
Ozymandias
  • 839
  • 1
  • 8
  • 13
  • 1
    Please post a [mcve]. What your question currently contains doesn't even use the ctor you are talking about. – Jesper Juhl May 30 '17 at 16:00
  • How *do* you use the class? What arguments do you actually provide to the constructor? If you provide a `double` *value* (and not a pointer to a `double`) then yes there will be an error. – Some programmer dude May 30 '17 at 16:00
  • 3
    _"Does the constructor just take the address of the double that the user provides? "_ Yes. I'm afraid I don't get your question? – πάντα ῥεῖ May 30 '17 at 16:00
  • You provide a variable that you're reading from a sensor for the input and a user defined/controlled variable for the setpoint value. – Ozymandias May 30 '17 at 16:02
  • 3
    yes - the user will get an error if they pass a double to a function that expects a pointer to a double. No the 'address of' is not done . Show some code that you expect to fail but that is working – pm100 May 30 '17 at 16:04
  • My apologies. It's been a while since I've used this library and I now remember coming across this issue a few years ago. The constructor takes the arguments as follows; PID YawdtPID(&Yawdt, &YawdtOut, &Ch1, GyroZP, GyroZI, GyroZD, DIRECT); It doesn't work unless uou use the “address of” operator on the first three arguments – Ozymandias May 30 '17 at 16:07
  • 1
    That is exactly as expected. The address of operator is how you get a pointer. – David Grayson May 30 '17 at 16:12

1 Answers1

1

There are a few possible explanations for this.

optional argument:

One possible explanation is that Setpoint is optional, so you can pass nullptr.

In the code, if you passed a null pointer, no setpoint is used.

You have mentioned that Setpoint gets dereferenced in another function, so it's likely not optional.

out-param:

C doesn't have references, so out-params are typically passed as pointers. In order to make a change to a parameter which is visible to the caller of the function, you pass it as a pointer

void setFoo(double* in)
{
    *in = 5;
}

double foo;
setFoo(&foo); // pass the memory address of your variable

At this point foo has the value of 5.

In C++ you can use references, so if you wanted to have an out-param, but require the user provide a value, you would use double& Setpoint.

allow external changes to be visible:

Probably the most likely explanation is to allow you to provide the address of Setpoint, and then if you change the value of Setpoint later, the object will observe those changes.

double setpoint = 1;

PID p(&input, &output, &setpoint, ...)

p.foobar(); // setpoint=1 

setpoint = 3;
p.foobar(); // setpoint=3

Again, in C++ you could use a reference to get this same behaviour (although that would make your object non-assignable).

As you can see there are several possible explanations, so without further details you can't really say for sure why the library author requires you to use a pointer instead of by-value semantics

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213