Link to home
Start Free TrialLog in
Avatar of JohnSantaFe
JohnSantaFe

asked on

problem printing out c++ enum

Hi,

Here's the information:  VS2005, using c++.  I am trying to print out an enum value (as a string), and it works the first time, but not during any subsequent times.  I'm wondering if there is just some obscure thing I don't know.  Below is my code, Here is an explanation:

We have a custom TCP channel based object that can send and receive commands.  That is what 'channel' is.  Note that myEnum is just an enumeration with a bunch of commands in it.  Please note that receiving the first command works fine and prints out fine too.  However, cmd2 will not print out.  What is even more bizarre is that the little floaty box thing when stepping through the program in Visual Studio DOES confirm that cmd2 is correct!!!  It was received!  But there is nothing on the console when printing.


      myEnum cmd;
      this->channel->ReceiveCommand(&cmd);
      std::cout << "We should have received ERRCORR_BEGIN.  Command received == " << cmd << std::endl;

      #if _DEBUG
            myEnum cmd2;
            this->channel->ReceiveCommand(&cmd2);
            std::cout << "We should have received GET_BITS.  Command received == " << cmd2 << std::endl;
        #endif


You may note that the ReceiveCommand function takes a reference.  In reality, it takes a pointer to a myEnum.  So, I have tried all sorts of things with regards to using pointers, and printing out the addresses of the commands using both the & and the * operators, all to no avail.  No matter what I do, the first one prints and the second one doesn't.

Thanks for any help.

Regards,
Michael Kolakowski

P.S.  I assign this a difficult rating, only because it's so simple and yet not working....what more could I be missing?
Avatar of sajirochira
sajirochira

When you are stepping through the program, the cmd2 prints well, right?
But when you run the program, it is not working??
Please make sure that you are executing a debug version. Then only the the cmd2 will be printed, as there is a #if _DEBUG clause.

HTH
Saji R
Avatar of JohnSantaFe

ASKER

No, it does not print...ever!  I can run it in debug, release, whatever.  I can remove the #if so it will always run and the same thing happens...it never, ever, prints out.  But it does show up in the intellisense thing.  Quite frustrating I might add.

Michael Kolakowski
Hi JonSantaFe

Please specify your declaration of the myEnum tpye (or class ?).
And please let us see the declartion of the ReceiveCommand method.

Cheers,
Sebastian
There are two things I'm thinking.
1. I'm suspicious of the #if
so can you please insert the foll before the #if and try. Understood that you've tried removing #if line.

#ifndef _DEBUG
#define _DEBUG
#endif

2.  Does any of the second line print out?? i.e. this bit
"We should have received GET_BITS.  Command received =="
If none of it is printed then I would be even more suspicious of your #if.
If the text does print then what value are you getting from the cmd2 printout.




   

First, the enum looks something like this:

enum myEnum{
      LOG_IN = 1,
      ABORT,
      LOG_OUT,
      LOG_OUT_OK, /* Server responses */                       
        READY,
      LOG_IN_OK,
      LOGIN_FAILED,
        CMD_OK,
      CMD_FAILED,
      CMD_INVALID,  //25
};

And the receive command looks a bit like this:

int TCPChannel::ReceiveCommand(const ChannelCommand *cmd)
{
      int bytesIn = 0;
      int recvStatus = SOCKET_ERROR;
                  
        recvStatus = recv(conn,(char *) cmd,sizeof(ChannelCommand),0);
            
      if (recvStatus <= 0 )
            cout << "Error receiving data in TCPChannel::ReceiveCommand. WSA error code: " << WSAGetLastError() << endl;

      bytesIn += sizeof(ChannelCommand);
      totalBytesIn += bytesIn;
      return bytesIn;
}

Note: both have been edited slightly, but this shouldn't affect things.  Thanks again.

Michael Kolakowski
This is regarding the comment on 6/25/06:

1. I tried that and it didn't do anything.  It just skipped over that part because I was building it in debug.

2. That's a very good question, and one I didn't clarify earlier.  Yes the second line prints out...it just prints nothing for the command.  So, it looks like this:

"We should have received GET_BITS.  Command received ==   "

Again, I can get it to print an address or pointer or whatever...but when I dereference the pointer (or reference variable) nothing comes out.  Plain old nothing.  But something is there, because the program runs fine.  So, I shouldn't be complaining too much.  I'm just so befuddled as to why the first one works, but the second one doesn't.

As a further clarification to my earlier code post: the enum is actually called channelcommand.  I was trying to hide as much project related detail as possible because we are not supposed to discuss it, however, I see that I let the cat out of the bag in the receive command function, so consider it explained.

Michael Kolakowski  
Hi JohnSantaFe,


You are passing an argument of type myEnum to the member function TCPChannel::ReceiveCommand(const ChannelCommand *).
That is bound to eventually cause an exception. I suspect your code crashes upon first access to the variable cmd.

Also, the member function TCPChannel::ReceiveCommand(const ChannelCommand *) cannot not possibly alter its argument, as it is const.

If ReceiveCommand is to return incoming TCP data, the declaration of this member function ought to be:
    int TCPChannel::ReceiveCommand(ChannelCommand *cmd)

Your are using the ChannelCommand object as second argument to the recv(..., cmd, ...)
In order for this to work, ChannelCommand must be of type char* and already allocated.
It would help to know what the ChannelCommand class looks like.

Finally, assuming ChannelCommand represents a string, the returned buffers cmd, cmd2, respectively MUST be terminated with '\0' in order for cout to function properly. Otherwise there is no way of telling how long the string is. (I am assuming ChannelCommand  is somhow derived from a string class.

Usually you would use recv(...) as such:

char buffer[1024];
int nBytes;                // Number of bytes actually received

//** receive maximum of 1023 bytes in buffer
//** one byte less than actually available to leave space for termininating '\0'
nBytesReceved = recv(conn, buffer, 1023, 0)

//** terminate string in 'buffer with ''\0'
buffer[nBytes] = '\0'

TRACE2("We received %i bytes:\n %s\n", nBytes, buffer);



Try the following:

ChannelCommand  cmd;

     this->channel->ReceiveCommand(&cmd);
     std::cout << "We should have received ERRCORR_BEGIN.  Command received == " << cmd << std::endl;

     #if _DEBUG
          ChannelCommand  cmd2;
          this->channel->ReceiveCommand(&cmd2);
          std::cout << "We should have received GET_BITS.  Command received == " << cmd2 << std::endl;
        #endif


Darn  - my browser submitted the comment before I was ready.
Do post your ChannelCommand  class definition  or test the recv - function as I posted.

Cheers,
sebastian
John,
int TCPChannel::ReceiveCommand(const ChannelCommand *cmd)
 cannot modify the ChannelCommand variable because it is const.

Try removing the const from the ReceiveCommand function (also the prototype).

This would explain why you could see it working when tracing it in visual studio.  

J.

Guys....you got me all excited by your posts, but alas, they still were not the solution.  Allow me to explain and address questions:

1. Remember, I changed my code to hide project details, but forgot to change all of it.  Hence any inconsistencies.

2. There is no channelcommand class.  It is an enum.  That's it.  Pleae replace channelcommand with myEnum or vice versa.  Whatever floats your boat.

3. Finally, (here's the part the got my hopes up), the const trick doesn't work either.  Note that ReceiveCommand takes a constant pointer to a channel command, which is different from a pointer to a constant channel command.  So, indeed, it CAN modify the variable, because the variable is not const, it just can't change the pointer.  Shucks...

So, it looks like we are back to square one again!

Michael
Hi,

Seeing as this appears to be so hard, I thought we'd have a double points Thursday!  Woohoo.

Michael
Hi JohnSantaFe

It is quite hard to spot a logical mistake in some code when it is covered up by several others.
Why not just create a code snipped that would theoretically run, so we can talk about your actual problem ;-)

It's just not so intuitive to interchange types and classes - this is not VB you know ;-)
And how about the 'const' argument to ReceiveCommand() - is that also a disguise, so we won't notice it beeing changed ...

As to your point 3:
# const Fred* p means "p points to a Fred that is const" — that is, the Fred object can't be changed via p.
# Fred* const p means "p is a const pointer to a Fred" — that is, you can change the Fred object via p, but you can't change the pointer p itself.


The recv function will alter the memory pointed to by 'cmd', not cmd itself. I tried to explain that you will need to allocate memory at 'cmd' if you are using it as you do:
recv(conn, cmd, nBytesAllocatedAtAddressCmd, 0);

Cheers,
Sebastian






Its a strange problem then.
I have created some code that I think represents your code. It won't compile on my machine because of the foll function:
int ReceiveCommand( const myEnum *cmd)

It does compile and works when the function is int ReceiveCommand( myEnum *cmd)
If we uncomment the foll line it also works:
//recv((char *) cmd);


Does this code describe your code??


#include <string>
#include <iostream>

enum myEnum
{
     LOG_IN=1,
     ABORT,
     LOG_OUT,
     LOG_OUT_OK, /* Server responses */                      
        READY,
     LOG_IN_OK,
     LOGIN_FAILED,
        CMD_OK,
     CMD_FAILED,
     CMD_INVALID,  //25
};
std::string& operator<<(std::string& strTarget, myEnum mE)
{//to get a string output for myEnum
    if (mE == LOG_IN)
        strTarget = "LOG_IN";
    else if (mE == ABORT)
        strTarget = "ABORT";

    else if (mE == LOG_OUT)
        strTarget = "LOG_OUT";
    else
        strTarget = "????";

    return strTarget;
}
void recv(char * cmd)
{//disguise the fact I'm changing things
      char newVal=1;
      char *newptr=&newVal;
      //*newptr='6';
      *cmd=newVal;//newptr;

};
//
int ReceiveCommand( const myEnum *cmd)
{
     int bytesIn = 0;
     char somchar='0';
       *cmd=LOG_IN;
            //recv((char *) cmd);

     return 5;
}

int main()
{

       myEnum cmd;
       std::string strFormat;
       ReceiveCommand(&cmd);
      strFormat << cmd;
std::cout << "We should have received LOG_IN.  Command received == " << strFormat << std::endl;
      
      
    // #if _DEBUG
          myEnum cmd2;
          ReceiveCommand(&cmd2);
         strFormat << cmd;
 std::cout << "We should have received LOG_IN.  Command received == " << strFormat << std::endl;
     //   #endif


      return 0;
}
Here is an interesting snippet of code regarding const variables.

const int x = 4;           // x is const, it can't be modified
const int* pX = &x;        // you can't modify x through the pX pointer

std::cout << x << "\n";         // prints "4"

int* pX2 = (int *)pX;      // explicitly cast pX as an int*
*pX2 = 3;                  // result is undefined

std::cout << x << "\n";        // who knows what it prints? on mine if prints 4.

Its a strange problem then.
I have created some code that I think represents your code. It won't compile on my machine because of the foll function:
int ReceiveCommand( const myEnum *cmd)

It does compile and works when the function is int ReceiveCommand( myEnum *cmd)
If we uncomment the foll line it also works:
//recv((char *) cmd);


Does this code describe your code??


#include <string>
#include <iostream>

enum myEnum
{
     LOG_IN=1,
     ABORT,
     LOG_OUT,
     LOG_OUT_OK, /* Server responses */                      
        READY,
     LOG_IN_OK,
     LOGIN_FAILED,
        CMD_OK,
     CMD_FAILED,
     CMD_INVALID,  //25
};
std::string& operator<<(std::string& strTarget, myEnum mE)
{//to get a string output for myEnum
    if (mE == LOG_IN)
        strTarget = "LOG_IN";
    else if (mE == ABORT)
        strTarget = "ABORT";

    else if (mE == LOG_OUT)
        strTarget = "LOG_OUT";
    else
        strTarget = "????";

    return strTarget;
}
void recv(char * cmd)
{//disguise the fact I'm changing things
      char newVal=1;
      char *newptr=&newVal;
      //*newptr='6';
      *cmd=newVal;//newptr;

};
//
int ReceiveCommand( const myEnum *cmd)
{
     int bytesIn = 0;
     char somchar='0';
       *cmd=LOG_IN;
            //recv((char *) cmd);

     return 5;
}

int main()
{

       myEnum cmd;
       std::string strFormat;
       ReceiveCommand(&cmd);
      strFormat << cmd;
std::cout << "We should have received LOG_IN.  Command received == " << strFormat << std::endl;
      
      
    // #if _DEBUG
          myEnum cmd2;
          ReceiveCommand(&cmd2);
         strFormat << cmd;
 std::cout << "We should have received LOG_IN.  Command received == " << strFormat << std::endl;
     //   #endif


      return 0;
}
oops. double comment.
Thanks everyone for all your efforts in trying to help.  Puta, it appears your code does closely match my code.  I was even thinking of going the route you did.  I have not had the easiest time finding information online about enums.  But I did notice this:  Puta, you had if statements in your code of the form:

if (cmd == WHATEVER)
  std::cout << "WHATEVER" << std::endl;

Whereas I was trying to directly output the Enum (std::cout << "enum is: " << cmd << std::endl;).  Is that even valid?  If not, then why does it work the first time for me?  That's the confusing part.  I could understand if you just couldn't print out enums, then I would have gone with the 'intermediate' block of code to get the string representation -- but it DOES work!!!!  WHY?

By the way, I already tried doing a block of code like yours, Puta, to get the string representation of my ChannelCommands.  It works just fine.  So, I guess I'm maybe being picky and esoteric in really insisting on sending the enum (ChannelCommand) to standard out.

Thoughts?  Comments?


Thanks,
Michael  
Hi Michael,

The operator <<  will take your enum as an integer value and print it out as such.
so:

enum {one=1, two, three, four};
std::cout << one << " : " << two << " : " << three << std::endl;

wil yield the output:
1 : 2 : 3


Cheers,
Sebastian


Bastibartel,

I wanted to address some of your comments.  I will do so now along with your latest response.  First, your message from 6/30 at 2:56:

I did not think the code was so complex that a few typing mistakes would hurt it.  We're experts here, right?  Also, the tone of your e-mail (yes, I know electronic communications are awful for connotation) seems to indicate near sarcasm to me.  I want you to know I'm not trying to hide anything.  Regarding the const problem, I mentioned that I tried it both ways -- it still didn't work.  And, regarding the pointers, I apologize.  It's always such a pain to keep those straight.  Also, I don't program in VB, and I'm actually a decent programmer.  I 'do' know the difference between types and classes, however Python and the str() function are great!  Finally, I don't think I mentioned this, but I tried allocating memory for my cmd using the new operator.  IT DID NOT WORK!  I tried putting it on the heap, the stack, using pointers, using new, you name it...all to the same results:  It just prints nothing.

That said, I'd now like to address your latest post.  On my computer, I do not get the results you claim.  Operator << does NOT take my enum as an integer unless I specifically cast it as thus:

std::cout << (int) enumvalue << std::endl;

Secondly, I cannot stress this enough times:  For the first statement in my code it actually works.  It actually prints out the string representation of the enum value.  Using your example, that is:

std::cout << one << " : " << two << std::endl;

yields the out put:
one : two

Please see my very first post for further clarification.  The first statement works, the second doesn't.  It's that simple.  Which makes it all that much more frustrating for me.  And the heck with the #if _DEBUG -  guess what?  taking that out made no difference either.  I wouldn't be posting here if they both worked or both didn't.  If they both worked, obviously I'd be fine, and if they both didn't, well, I'd have just assumed that you can't send an enum to std::cout and would have used a switch or something to get the string representation.  But, again, one works, the other doesn't and there is no discernable difference between the two.

Note: I did try figuring out someway to append a '\0' on to the enum...but I'm not an uber programmer, so that venture was met with no success.  I thought perhaps if I could be sure it was null terminated (though I thought cout was 'smarter' than printf) that might help.  Again, I couldn't figure out how, an enum is not a char buffer, so memcpy didn't work among other things.

Take care and have fun!

Michael Kolakowski
SOLUTION
Avatar of bastibartel
bastibartel

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well, I think it's time to close the book on this one.  I've had enough.  First, a few things to say:

Sebastian, thanks for the apology and don't sweat it.  I have a pretty thick skin so I don't take offense too easily.  Besides, you never know if you are dealing with a total noob or someone who has programmed in 12 languages.  Perhaps there should be a way to list your experience so you experts have a basis for your response.  Maybe this could be a feature added to the site?  I've read that even Eric Raymond gets stumped from time to time and he's written compilers for fun, something I've yet to do!  

You are probably right about discussing code, but again I only altered names and not the code.  I just forgot to change all of them. ;)  Also, for what it's worth, only the output code is mine.  The enum, receive command, and such were written by someone else.

Putanerd, thanks again for your response.  On a whim, I thought I'd try it one more time.  I removed the const, called receive command as you suggested and it still doesn't work.  ~sigh~  Perhaps you are right about it being an undefined result.  In any case, my solution is to do this:

                ChannelCommand cmd2;
            this->channel->ReceiveCommand(&cmd2);

            //short story: I've had major problems with this.  So this is my work-around
            //Call Michael or see: https://www.experts-exchange.com/questions/21895679/problem-printing-out-c-enum.html
            string command = "Step through code to find command";
            if(cmd2 == GET_BITS)
                  command = "GET_BITS";

            std::cout << "We should have received GET_BITS.  Command received == " << command << std::endl;

Our enum has some 30 values in it, and it's one of many enums....so I didn't want to do that whole operator << overload thing.  This works for now.

As such, I'll be splitting the points due to both of your efforts.  They are much appreciated.  It's time we all move on to better and more important things.

Take care,
Michael
Take care - and good luck.
best of luck. Drop us a line if there are any further problems.


J.