Solved

problem printing out c++ enum

Posted on 2006-06-22
24
363 Views
Last Modified: 2008-02-01
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?
0
Comment
Question by:JohnSantaFe
  • 8
  • 8
  • 7
  • +1
24 Comments
 

Expert Comment

by:sajirochira
ID: 16960992
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
0
 

Author Comment

by:JohnSantaFe
ID: 16961171
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
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 16966491
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
0
 
LVL 1

Expert Comment

by:putaNerd
ID: 16981331
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.




   

0
 

Author Comment

by:JohnSantaFe
ID: 16996826
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
0
 

Author Comment

by:JohnSantaFe
ID: 16996922
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  
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 16997104
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


0
 
LVL 5

Expert Comment

by:bastibartel
ID: 16997114
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
0
 
LVL 1

Expert Comment

by:putaNerd
ID: 16999765
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.

0
 

Author Comment

by:JohnSantaFe
ID: 17002888
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
0
 

Author Comment

by:JohnSantaFe
ID: 17012932
Hi,

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

Michael
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 17016557
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






0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Expert Comment

by:putaNerd
ID: 17025560
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;
}
0
 
LVL 1

Expert Comment

by:putaNerd
ID: 17025564
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.

0
 
LVL 1

Expert Comment

by:putaNerd
ID: 17025591
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;
}
0
 
LVL 1

Expert Comment

by:putaNerd
ID: 17025642
oops. double comment.
0
 

Author Comment

by:JohnSantaFe
ID: 17031172
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  
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 17031336
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


0
 

Author Comment

by:JohnSantaFe
ID: 17031812
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
0
 
LVL 5

Assisted Solution

by:bastibartel
bastibartel earned 250 total points
ID: 17036111
Hi Michael,

I actually was beeing sarcastic and I am sorry for that. At the same time though I was trying to make it sound very moderate and never meant to depreciate you.
The electronic communication won't transmit tone of voice - will it.

It is sometime really hard to tell on what level of difficulty one is supposed to answer the question.
So given the type mixups, given the const* pointer, given the usage of the recv() function I had to assume these were you troubles.

I still believe you cannot reasonably discuss a piece of (possibly errornous) code that has been been altered the way you did.
You know your code best by the time of posting. We must believe that all you are posting is of certain relevance to the problem - otherwise you wouldn't have posted it.

I am sorry for generalizing my statement about the implicite enum -> int cast. My compiler does it, yours obviously doesn't.
However, given that your compiler prints out " one : two : three" I will have to resign now as I obviously know nothing about programming envirnonments other than my VC6++
*sarcasm* -> me.

Again I am sorry for picking that harsh tone of voice
Sebastian


0
 
LVL 1

Accepted Solution

by:
putaNerd earned 250 total points
ID: 17041533
John,
I'm not sure how much experience basti has, probabably a fair bit and i've been in the software industry for a while now, it is hard without seeing all the code but we both suspect there is something up with both the handling of pointers and the use of CONST.

I suspect that the problem with your code might be that it does not conform to the standards. i.e. the way it is written relies on an undefined action, it will work sometimes but is not guaranteed, like the code previously described:

"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."

It might pay to revisit parts of the code.
My advice from here would be to make your ReceiveCommand function look like this:
int ReceiveCommand(myEnum *cmd)
call it with
ReceiveCommand(&cmd); where cmd is defined     myEnum cmd=myEnum(0); //making sure memory is allocated

Inside ReceiveCommand call recv with this

 recvStatus = recv(conn,(char *) cmd,sizeof(myEnum),0); //consider using 1 instead of sizeof(myEnum), you actually only want 1 digit from recv - this is just my guess.)

then make it compile without the use of any extra * or &'s, unless absolutely neccesary.



*********************************
The block of string text you are talking about is the << operator overload function for the myEnum datatype. It provides an easy way to print out strings, such as  "LOG_IN" rather than dealing with a number. Your code, as is, would print  '1' mine would actually print  "LOG_IN."
To use, its the same as any std output.
std::cout <<cmd;


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;
}



its a bit wordy, but hopefully gives you something to go off.

J.
0
 

Author Comment

by:JohnSantaFe
ID: 17043327
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: http://www.experts-exchange.com/Programming/Q_21895679.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
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 17043370
Take care - and good luck.
0
 
LVL 1

Expert Comment

by:putaNerd
ID: 17048628
best of luck. Drop us a line if there are any further problems.


J.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Suggested Solutions

Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now