Implementing C++ Output Streams

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
blah569
Posts: 16
Joined: Wed Feb 07, 2007 9:57 pm
Location: America
Contact:

Implementing C++ Output Streams

Post by blah569 »

[I have split this topic from here as it's quite a change of subject! - AJ]
Firestryke31 wrote:A preliminary screenshot of the latest iteration of my OS, "Socks."
SocksPrelim.png
I've got physical/virtual memory management, a simple initial display driver, and have just implemented ISR support. Next I have to implement the system call interface so I can get the IPC system running so I can get the driver interface set up.

The initial display driver, simple kernel heap, and physical memory manager are all C++ classes. The display driver even uses << for text and integers.
Looks really nice, and pretty convenient to be able to use "<<"
There's no place like 127.0.0.1.
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: What does your OS look like? (Screen Shots..)

Post by Firestryke31 »

Yeah, when I first set it up I was amazed at how easy it was to do. Just overload the global functions class& operator<<(class& in, const char* str) for strings and class& operator<<(class& in, const unsigned int) for integers. In my setup these then call class functions to do the actual display, but some just have them as "friend" and make them do the real work. Finally, just return in and you're done.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: What does your OS look like? (Screen Shots..)

Post by Creature »

Firestryke31 wrote:Yeah, when I first set it up I was amazed at how easy it was to do. Just overload the global functions class& operator<<(class& in, const char* str) for strings and class& operator<<(class& in, const unsigned int) for integers. In my setup these then call class functions to do the actual display, but some just have them as "friend" and make them do the real work. Finally, just return in and you're done.
Same here, the only thing I ran into was the ambiguity for chars and integers. I ended up using a small 'hack' that prints a character when you use character formatting (e.g. 'c') and always prints an integer when you enter a number (even if that number could be a character). If you absolutely want a number to be printed as char, you'd have to enter either unsigned char(number) or char(number) or something.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: What does your OS look like? (Screen Shots..)

Post by AJ »

Hi,
Creature wrote:Same here, the only thing I ran into was the ambiguity for chars and integers. I ended up using a small 'hack' that prints a character when you use character formatting (e.g. 'c') and always prints an integer when you enter a number (even if that number could be a character).
Another way to deal with this is by inserting an enumeration in to the stream. For example:

Code: Select all

myOutputClass << myOutputClass::Hex << 'a';            // displays '0x61'
myOutputClass << myOutputClass::Decimal << 'a';      // displays '97'
myOutputClass << myOutputClass::Character << 'a';   // displays 'a'.
So the enumeration acts as a type modifier for formatting the output. If you do this, I would suggest that you create the output class with a default output type - for example hexadecimal. This way, once the class receives the character, it automatically reverts to hex and so you don't have to explicitly send the state enumeration prior to every character write.

Cheers,
Adam
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Implementing C++ Output Streams

Post by pcmattman »

This way, once the class receives the character, it automatically reverts to hex and so you don't have to explicitly send the state enumeration prior to every character write.
Alternatively, have the class keep track of the last state enumeration used:

Code: Select all

outputClass << outputClass::Hex << 0xdeadbeef; // "0xdeadbeef"
outputClass << 0xf00d; // also "0xf00d"
outputClass << outputClass::Dec << 1234; // "1234"
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Implementing C++ Output Streams

Post by AJ »

Hello,
pcmattman wrote:Alternatively, have the class keep track of the last state enumeration used:
Equally valid, but my reason for avoiding this would be:

Code: Select all

outputClass << outputClass::Hex << 0xdeadbeef; // "0xdeadbeef"

myIntialisationFunction();  // may or may not use outputClass (I know - global objects == bad :o) )

if(something)
{
  outputClass << 0x1234;
}
else
{
  outputClass << outputClass::Dec << 5678;
}

outputClass << 0xf00d; // also "0xf00d" - or is it?
outputClass << outputClass::Dec << 1234; // "1234"
I would rather have the class reverting to a known state, because otherwise you could very easily have the situation where each call to the output steam uses the enumeration "just in case" it hasn't been left in the appropriate state.

Just personal opinion :)
Adam
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Implementing C++ Output Streams

Post by Solar »

You can't really define this any different than the ios_base modifiers from the C++ standard library do, because otherwise you would have two ways to do output that look identical but aren't really (Bad Thing (tm)).

And ios_base modifiers are "sticky", i.e. they remain valid until overruled by some other modifier.
Every good solution is obvious once you've found it.
User avatar
Firestryke31
Member
Member
Posts: 550
Joined: Sat Nov 29, 2008 1:07 pm
Location: Throw a dart at central Texas
Contact:

Re: Implementing C++ Output Streams

Post by Firestryke31 »

The entire purpose of my class was to have some basic way of getting info to the screen so I could debug until I got the proper CRT and display drivers running, which won't be for a while. I didn't care about being just like the C++ STL's cout. YMMV.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: What does your OS look like? (Screen Shots..)

Post by Creature »

AJ wrote:Hi,
Creature wrote:Same here, the only thing I ran into was the ambiguity for chars and integers. I ended up using a small 'hack' that prints a character when you use character formatting (e.g. 'c') and always prints an integer when you enter a number (even if that number could be a character).
Another way to deal with this is by inserting an enumeration in to the stream. For example:

Code: Select all

myOutputClass << myOutputClass::Hex << 'a';            // displays '0x61'
myOutputClass << myOutputClass::Decimal << 'a';      // displays '97'
myOutputClass << myOutputClass::Character << 'a';   // displays 'a'.
So the enumeration acts as a type modifier for formatting the output. If you do this, I would suggest that you create the output class with a default output type - for example hexadecimal. This way, once the class receives the character, it automatically reverts to hex and so you don't have to explicitly send the state enumeration prior to every character write.

Cheers,
Adam
I'm also using the enumeration approach for std::hex, std::bin, std::oct, etc. (they are just custom values in an enumeration that act similar to the standard library). For characters, I've thought of this approach as well, but I found it to be rather inconvenient to have to type that every time, so I just stuck with the 'g' and char(200) approach.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Implementing C++ Output Streams

Post by AJ »

Hi,
Solar wrote:You can't really define this any different than the ios_base modifiers from the C++ standard library do, because otherwise you would have two ways to do output that look identical but aren't really (Bad Thing (tm)).
One of the rare times I disagree with Solar :)

IMO, if you're keeping this internal and do not use the same naming system as the Standard Library, then it's OK to do it differently [ducksandruns]. On the other hand, if you plan doing this in the std:: namespace and then decide to include your new system in your user library, that's different :)

Cheers,
Adam
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Implementing C++ Output Streams

Post by Owen »

The thing is you end up with two interfaces which are 99% the same and 1% different.

Too confusing, IMO.

(Though I've never liked C++ input streams anyway; output streams are OK, but printf is better)
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Implementing C++ Output Streams

Post by AJ »

Hi,

For the sake of not coming back to a religious war when I next come online, I'll admit "It may not be the best idea from a standards point of view, but it works well in practice I do it anyway." ;)

In my defense, I should point out that where I do name stuff in the same way as a standard dictates (malloc, free, printf...), I'm anally retentive about ensuring it does follow the standard to the letter.

Cheers,
Adam
Post Reply