error msg: expected unqualified-id before string constant

I am trying to implement a library RotaryEncoder.h, I was unable to get the main file to see the variable "change" so thought that it may have needed some help with linkage so added the #ifdef __cplusplus code to it.

I have been getting the error msg: expected unqualified-id before string constant the IDE highlights the line: extern "C" about half way down the page.

#ifndef __RotaryEncoderIncluded
#define __RotaryEncoderIncluded
class RotaryEncoder
  {
    unsigned int state;
    int pin2, pin9;
    int ppc;
    int change;
    unsigned int readState()
      {
        return (digitalRead(pin2) ? 1u : 0u) | (digitalRead(pin9) ? 2u : 0u);
      }
  #ifdef __cplusplus
  extern "C" 
    {
      #endif //cplusplus  
      public:
        RotaryEncoder(int p2, int p9, int pulsesPerClick) : 
        pin2(p2), pin9(p9), ppc(pulsesPerClick), change(0), state(0) {}
        void init();
        void poll();
        int getChange();
    };
  #ifdef __cplusplus
  } // end class RotaryEncoder
  #endif //cplusplus
#endif //RotaryEncoderIncluded

here is the listing of error messages:

In file included from RotaryEncoder.cpp:1:
RotaryEncoder.h:14: error: expected unqualified-id before string constant
RotaryEncoder.cpp:56: error: expected `}' at end of input
/RotaryEncoder.h: In member function 'unsigned int RotaryEncoder::readState()':
RotaryEncoder.h:11: error: 'digitalRead' was not declared in this scope
/RotaryEncoder.h: At global scope:
RotaryEncoder.h:12: error: expected unqualified-id at end of input

The extern keyword is used to declare a variable in one file that is defined in another file. Most people use define and declare as being the same. They are not. A declaration builds an attribute list, but does NOT allocate memory for it. A function prototype is an example. A definition also builds an attribute list, but does allocate space for it. The extern keyword is used to declare a variable that is defined in another source file. In your case, if "C" is an int, the proper declaration is:

extern int C;

Using it with the syntax you have is string to treat "C" as a string. If it is a character array, then it would be:

extern char C[];

Without more details, I can only guess about the nature of the actual definition of C.

Thank you, I will try both solutions and see what happens. And thank you for the clarification. The error messages may be in English but are as cryptic as Kanji characters to the uninitiated.

Does this hep?

luisilva: Does this hep?

Well, sort of. It shows I have the syntax letter for letter correct. Placement or implementation may be in error but at least the syntax is right. Sorry, EconJack, the ifdef statements about "C" are referring to C the language, not an int or char so I do not see either solution applies, not that I understand the ifdef statement either, just cutting and pasting at this point .

You’re chasing a red herring. You don’t need any of the extern C crap at all. Neither did the poster in that thread that was linked above. All he needed to do was change the file extension from .c to .cpp so the compiler would treat it as C++.

The reason you can’t see the member change from your other code is because it is declared as private. All members of a class are private unless you say otherwise.

I did a test with this code:

#ifndef __RotaryEncoderIncluded
#define __RotaryEncoderIncluded
#include <Arduino.h>
class RotaryEncoder
  {
    unsigned int state;
    int pin2, pin9;
    int ppc;
    int change;
    unsigned int readState()
      {
        return (digitalRead(pin2) ? 1u : 0u) | (digitalRead(pin9) ? 2u : 0u);
      }

      public:
        RotaryEncoder(int p2, int p9, int pulsesPerClick) : 
        pin2(p2), pin9(p9), ppc(pulsesPerClick), change(0), state(0) {}
        void init();
        void poll();
        int getChange();
  }; // end class RotaryEncoder
#endif //RotaryEncoderIncluded

and compiles. So, What is the need of the “__cplusplus” thing?

luisilva: I did a test with this code: and compiles. So, What is the need of the "__cplusplus" thing?

Thanks, cut an pasted your working code and it is not throwing an error for that part, moving on to the main program errors. The "__cplusplus" thing?" was due to the main program not seeing the value of the "change" var I thought that the issue may have been mangling when compiling

Out of curiosity, some includes have " " and some have < >

#include “Goldelox_Serial_4DLib.h”
#include <SoftwareSerial.h>

What is the difference and when to use one over the other?

Chrissi:
(…) due to the main program not seeing the value of the “change” var I thought that the issue may have been mangling when compiling

As “Delta_G” said, you jus can’t see the value of “change” because is private.

Chrissi:
Out of curiosity, some includes have " " and some have < >

#include “Goldelox_Serial_4DLib.h”
#include <SoftwareSerial.h>

What is the difference and when to use one over the other?

About this question, if the library is global use <> if the library is local (ex. placed on your sketch folder) use “”.

“if the library is global use <> if the library is local (ex. placed on your sketch folder) use “”.”
Thank you, I’ll add that to my notebook.

if the library is global use <> if the library is local (ex. placed on your sketch folder) use “”

To add to this explanation, the brackets cause the compiler to look in the default include directory, whatever that might be. The double quotes causes the compiler to look in the current working directory for the include file. However, if the compiler does not find the include file there, it will then look in the default include directory. I think explaining this in terms of (scope) storage classes is misleading.

Thank you for the clarification on the < > & " ", I added that to my notes.

Onward and upward…
I tried moving the int change; declaration to the public: portion of RotaryEncoder.h, still get the message
‘change’ was not declared in this scope from the main program so seems RotaryEncoder.h is possibly not the cause?
Here is the main code

#include <Goldelox_Serial_4DLib.h>
#include <Goldelox_const4D.h>
#include <SoftwareSerial.h>
#include "RotaryEncoder.h" // using locally; file modified for pin assignments

SoftwareSerial DisplaySerial(8,7) ; // pin 8 = TX of display, pin 7 = RX of display. Required for 4DS
Goldelox_Serial_4DLib Display(&DisplaySerial); //use DisplaySerial to communicate with the display.

#define pinA 2 //rx encoder on pin 2, no longer utilizing interrupt 0
#define pinB 9 //rx encoder on pin 9

// ============================================
// ===================   Setup   ===================
// ============================================
void setup()
  {
    // --------------------------------- 4DS Display ----------------------------
    Display.TimeLimit4D   = 5000 ;   //5 second timeout on all commands to display
    //---------------------------------- Setup 4DS Reset ----------------------
    pinMode(4, OUTPUT);  // Set D4 on Arduino to Output. If using jumper wires, reverse the logic states below.
    digitalWrite(4, 1);  // Reset the Display via D4 
    delay(100);
    digitalWrite(4, 0);  // unReset the Display via D4 
    //--------------------------------- end 4DS Reset --------------------------
    delay (5000); // let the display start up     
    DisplaySerial.begin(9600); // begin com with the DISPLAY MODULE make sure that the display module has the same baud rate on splash screen
    Display.gfx_Cls(); // clear the screen
    // -------------------------------- end 4DS ---------------------------------
    Serial.begin(115200); // for serial monitor
   } // end setup
   
// ============================================
// ===================   Loop   ====================
// ============================================
void loop()
  {
    screen();
  } // end LOOP

// ============================================
// ===================   Functions   =================
// ============================================  
void screen() //
  {
    Display.gfx_Cls(); 
    Display.media_Init();
    Display.gfx_ScreenMode(LANDSCAPE); 
    Display.media_SetSector(0, 0) ; // must come b4 setting fontID
    Display.txt_FontID(MEDIA) ;
    Display.txt_BGcolour(BLACK) ;
    Display.txt_FGcolour(WHITE) ;
    
    if (change == 1)
      {
        Display.gfx_MoveTo(0 , 10) ;
        Display.putstr("CW");
      }
    if (change == -1)
      {
        Display.gfx_MoveTo(0 , 30) ;
        Display.putstr("CCW");
      }
  } // end screen

As is I do not expect the two to produce results until I get the linking with the header worked out, the encoder is supposed to be polled by MsTimer2.h every 2 millis avoiding the need to use up an interrupt needed later.

I don't see the definition of the object "RotaryEncoder". Where is it?

EDIT: You can't just do this:

    if (change == 1)

I think you should find a good tutorial on C++ and classes before you go any further and waste any more time. You obviously have no idea and you're trying to dig into some obscure compiler directives when you haven't even created an instance of your class. This is simple code. The problem is not going to be some weird extern line. I promise that botht he compiler and the linker included with the IDE can handle a simple class definition. If it couldn't don't you think you'd see more posts like this? You don't need to mess with the compiler or the linker, you need to learn to use classes.

You haven't created an instance of this class at all. You are trying to access the variable like it is in the scope of the main program which it is not. This is why they always ask for you to post ALL of your code. You just wasted the time of a number of people with this when you could have posted the stupid code and got the answer hours ago.

Class members usually get accessed with the dot operator. Something like this:

if (myRotEnc.change == 1)

Where myRotEnc is an instance of your RotaryEncoder class.

Thank you for the feedback. I have avoided using libraries other than provided ones -because- I clearly did not understand them, have done all writing within arduino sketches.

My needs have outgrown this and am making efforts to implement cut and pasted in libraries. Poorly yes. As I have demonstrated here I did not fully understand the concept. Why I came for help, not to waste your time.

I have spent the afternoon reading about libraries and classes. I 'll say my limited understanding is still limited but less so. I will massage my program and respond with the result.

Again, thank you for your patience.

Is there a best way to show the code for multiple files on a forum page? One code box for each one above the other?

Chrissi: Is there a best way to show the code for multiple files on a forum page? One code box for each one above the other?

That would work. You could even spread it out over multiple posts if there's a lot of it. Or you can attach it if it is really long.

Okay, here is the whole of it. This is a test program to determine if this encoder routine will work out for something else I want to do. I have tried other routines and was not satisfied with how they worked. This one was suggested elsewhere by member DC42 and sounded perfect for my needs. It compiles now (thank you to all that helped) without the above mentioned error yet at this point does not register a state change.

Here is the main part:

#include <Goldelox_Serial_4DLib.h>
#include <Goldelox_const4D.h>
#include <SoftwareSerial.h>
#include "RotaryEncoder.h" 
#include "MsTimer2.h"
SoftwareSerial DisplaySerial(8,7) ; // pin 8 = TX of display, pin 7 = RX of display. Required for 4DS
Goldelox_Serial_4DLib Display(&DisplaySerial); //use DisplaySerial to communicate with the display.
#define pin0 2 //rx encoder on pin 2
#define pin1 9 //rx encoder on pin 9
RotaryEncoder encoder(2, 9, 4); //left pin, right pin, pulses per click
int movement = encoder.getChange();

// =================================================
// ==================   Setup   ====================
// =================================================
void setup()
  {
    // ------------- 4DS Display ------------------
    Display.TimeLimit4D   = 5000 ;   //5 second timeout on all commands to display
    //----------- Setup 4DS Reset -----------------
    pinMode(4, OUTPUT);  // Set D4 on Arduino to Output. If using jumper wires, reverse the logic states below.
    digitalWrite(4, 1);  // Reset the Display via D4 
    delay(100);
    digitalWrite(4, 0);  // unReset the Display via D4 
    //------------- end 4DS Reset -----------------
    delay (5000); // let the display start up     
    DisplaySerial.begin(9600); // begin com with the DISPLAY MODULE make sure that the display module has the same baud rate on splash screen
    Display.gfx_Cls(); // clear the screen
    // -------------- end 4DS ---------------------
    Serial.begin(115200); // for serial monitor
    encoder.init();
    pinMode(pin0, INPUT);
    pinMode(pin1, INPUT);
    digitalWrite(pin0, HIGH);
    digitalWrite(pin1, HIGH);  
    MsTimer2::set(2, poll); // 2ms period, call function 'pol'
    MsTimer2::start();
   } // end setup
   
// =================================================
// ==================   Loop   =====================
// =================================================
void loop()
  {
    screen();
  } // end LOOP

// =================================================
// =================  Functions   ==================
// =================================================  
void poll()
  {
     encoder.poll();
  }
//--------------------------------------------------
void screen() //
  {
    //Display.gfx_Cls(); 
    Display.media_Init();
    Display.gfx_ScreenMode(LANDSCAPE); 
    Display.media_SetSector(0, 0) ; // must come b4 setting fontID
    Display.txt_FontID(MEDIA) ;
    Display.txt_BGcolour(BLACK) ;
    Display.txt_FGcolour(WHITE) ;
    Display.gfx_MoveTo(0 , 10) ;
    Display.putstr("Encoder");
    Display.gfx_MoveTo(0 , 25) ;
    Serial.println(movement); // getting 0's here
    if (movement == 1) // substituted 0 here and got CW on screen
      {
        Display.gfx_MoveTo(0 , 50) ;
        Display.putstr("CW");
      }
    if (movement == -1) // substituted 0 here and got CCW on screen
      {
        Display.gfx_MoveTo(0 , 75) ;
        Display.putstr("CCW");
      }
  } // end screen

Here is the RotaryEncoder.cpp

#include "RotaryEncoder.h"
#include <arduino.h>

void RotaryEncoder::init()
{
  pinMode(pin0, INPUT);
  pinMode(pin1, INPUT);
  digitalWrite(pin0, HIGH);   // enable internal pullup
  digitalWrite(pin1, HIGH);
  change = 0;
  delay(10);                  // ensure we read the initial state correctly
  state = readState();
}

void RotaryEncoder::poll()
{
  // State transition table. Each entry has the following meaning:
  // 0 - the encoder hasn't moved
  // 1 - the encoder has moved 1 unit clockwise
  // -1 = the encoder has moved 1 unit anticlockwise
  // 2 = illegal transition, we must have missed a state
  static int tbl[16] = 
  {  0, +1, -1, 0,    // position 3 = 00 to 11, can't really do anythin, so 0
    -1,  0, -2, +1,   // position 2 = 01 to 10, assume it was a bounce and should be 01 -> 00 -> 10  
    +1, +2,  0, -1,   // position 1 = 10 to 01, assume it was a bounce and should be 10 -> 00 -> 01
     0, -1, +1, 0     // position 0 = 11 to 10, can't really do anything
  };
  unsigned int t = readState();
  int movement = tbl[(state << 2) | t];
  if (movement != 0)
  {
    change += movement;
    state = t; 
  }
}

int RotaryEncoder::getChange()
{
  int r;
  noInterrupts();
  if (change >= ppc - 1)
  {
    r = (change + 1)/ppc;
  }
  else if (change <= 1 - ppc)
  {
    r = -((1 - change)/ppc);
  }
  else
  {
    r = 0;
  }
  change -= (r * ppc);
  interrupts();
  return r;
}

// End

And here is the RotaryEncoder.h

// Class to interface Arduino to rotary encoders
// D Crocker, Escher Technologies Limited, October 2011.
// This code may be freely used for any purpose
// but is supplied without warranty.
//
// Declare a rotary encoder like this:
//
// RotaryEncoder encoder(leftPin, rightPin, pulsesPerClick);
//
// where pulsesPerClick is normally 4.
// Every 1 millisecond or so, call:
//
// encoder.poll();
//
// To find how much the encoder has moved since you last asked, do this:
//
// int movement = encoder.getChange(); When you want to know how far the encoder has moved, call getChange(). 

#ifndef __RotaryEncoderIncluded
#define __RotaryEncoderIncluded
#include <arduino.h>
class RotaryEncoder
{
  unsigned int state;
  int pin0, pin1;
  int ppc;
  int change;

  unsigned int readState()
  {
   return (digitalRead(pin0) == HIGH ? 1u : 0u)
   | (digitalRead(pin1) == HIGH ? 2u : 0u);
  }

public:
  RotaryEncoder(int p0, int p1, int pulsesPerClick) : 
    pin0(p0), pin1(p1), ppc(pulsesPerClick), change(0), state(0) {}

  void init();
  void poll();
  int getChange();
};

#endif

What may seem to be Crap, Obvious, Stupid, or whatever your favorite pejorative is, I am a rank noob and have learned everything I know from this and other similar forums as I believe many other do considering this product was intended for educational and hobbyist purposes. I came -here- because I had tried everything I could to flip whatever bit it took to make it work, clueless as it may have appeared to some I felt it was better than just showing up and passively saying hi I am blond please write my code for me.
Hopefully the code above makes a little bit more sense. I have bashed it about for two days and have yet to change the state of the output.

BTW, the reason I tried all that other mess was linking the libraries was not the simple drop in and run thing I thought it might be, thinking the worst I dug for answers and that was what I came up with. Clearly I was wrong on that =)

".... yet at this point does not register a state change."

Any suggestions?