gethostname and other goodies

Posted by Trask on Wed 19 Aug 2009 04:21 PM — 9 posts, 41,081 views.

Australia #0
Hi all,

I wrote myself a little program, just to prove a concept to myself, which came back with very unexpected and varied results. Could someone take the time to explain these findings to me?

Test 0

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int main()
{
cout << "Computer Name : " << system("uname -n") << endl;

output:
MyComputerName
Computer Name : 0

Test 1

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>


using namespace std;

int main()
{
char hostName[128] = system("uname -n");
cout << "Computer Name : " << hostName << endl;

output:
test.cpp:12: error: array must be initialized with a brace-enclosed initializer

Why does this error occur everytime I try to initialize a variable with a function?

I also noticed somewhere whilst browsing the web for this problem, that #include <cstdlib> seems to be used instead of (stdio/stdlib).h Is this correct?

Test 2

#include <iostream>
#include <string>

using namespace std;

int main()
{
FILE *hostName;
hostName = popen("uname -n","r");
pclose(hostName);
cout << "Computer Name : " << hostName << endl;

output:
Computer Name : 0xbbd010

Test3

#include <iostream>
#include <string>

using namespace std;

int main()
{
char hostName[128];
cout << "Computer Name : " << gethostname(hostName,128) << endl;

output:
Computer Name : 0

And finally!

Test4

#include <iostream>
#include <string>

using namespace std;

int main()
{
char hostName[128];
gethostname(hostName, 128);
cout << "Computer Name : " << hostName << endl;

output:
Computer Name : MyComputerName

yay, it did what it was meant to do :)

The main concepts learnt seemed to be:

1) I can't initialise variables with functions
2) I can't call a function in the middle of a cout line and expect to get away with it.

Are these correct? And is there some reference that explains the functions in the common/standard C++ libraries? i.e. how do I find out what functions do what?

And now as it relates to TinyMud,

After all this testing, I added the following code:

globals.cpp
char hostName[128];

globals.h
extern char hostName[128];

comms.cpp
gethostname(hostName,128);
p* << "Welcome to TinyMud Server << VERSION << " running on " << hostName << "\n";

Is this the most efficient/correct way of implementing this?

And one final question: Is there a neater way of shutting down TinyMud, as opposed to killall tinymudserver ?

Sorry if this post is convoluted and lacking in logical progression, my mind is erratic at best.

Thanks heaps!
USA #1
Template:codetag
To make your code more readable please use [code] tags as described here.


Anyways, on #1, that's because you defined an array. I can't explain it exactly (because I'm tired and also every so slightly rusty with C), but you're trying to assign the return result of system() to an array (and system() returns an int anyways, according to (1)). 0 in #0 is the status return code from the 'uname' program... if you've ever done much C, it's the 'return 0' you put at the end of main().

On #2, a FILE* is a file descriptor, not a string. I believe it's meant to be used as a handle to the process you started with popen().

On #3, if you couldn't tell, gethostname() returns an integer, but it does copy to the buffer. That's why in #4 it worked, because you copied to the buffer and then used the buffer rather than the functions return code.


(1) http://www.cplusplus.com/reference/clibrary/cstdlib/system/
Amended on Wed 19 Aug 2009 04:35 PM by Twisol
USA #2
Twisol pretty much explained it.

Basically, I think you're running into extremely common frustrations with C/C++, namely that you can't just "do things" and have to jump through lots of hoops to do what seem like relatively simple tasks such as getting the output of a process. For example, yes, you can open a pipe to a process, but before you can use that output, you need to read out from the file until EOF, etc.

For all its benefits, C++ is most certainly not a terribly friendly language, and it doesn't make life easy. :-/

Some clarifications/elaborations on what Twisol said:
Quote:
1) I can't initialise variables with functions

You can, it's just that you weren't getting what you thought you were. The return values of the functions were not of the appropriate type. An integer is not an array of characters, for example.
Quote:
2) I can't call a function in the middle of a cout line and expect to get away with it.

You can, but the cout streaming will use the return values, whereas that function doesn't return the hostname -- it sets it into a buffer. (The reason is, basically, that it has to because of how C works -- it's a C library.) So you printed out the return value (which was 0) and the buffer was set, but you didn't print out the buffer.
Australia Forum Administrator #3
Quote:

And one final question: Is there a neater way of shutting down TinyMud, as opposed to killall tinymudserver ?



  commandmap ["shut"] = DoShutdown; // shut MUD down


A word of caution here, gethostname is, I think, synchronous.

What that means briefly is that it looks up the host name whilst blocking your program. Say it has to go to a DNS server, and doesn't find one, or find one quickly, your program may seem to "hang" for a few seconds.

As for the other things, I agree with the other guys. You need to pay close attention to the defined return codes for functions. Many functions simply return success or failure (often success is zero, but certainly not always). If a value is also returned it may well be through an argument that is passed by reference, or is a pointer.
Australia #4
Thanks very much for the replies guys,

Quote:
A word of caution here, gethostname is, I think, synchronous.

What that means briefly is that it looks up the host name whilst blocking your program. Say it has to go to a DNS server, and doesn't find one, or find one quickly, your program may seem to "hang" for a few seconds.


Would this therefore be one of those instance where a script would be a better means of implementing this?

I got the idea from DoT mud, but I couldn't figure out how they implemented it in their code, bit too complex for me.


Such a simple little program has already taught me a lot about C/C++. I think it might be a good idea to have a poke through that /usr/include/ directory David pointed me to.

Cheers for the help, having people to ask questions of certainly makes the trials of a newbie coder a little easier... for the newbie at least :P

Thanks again
Amended on Thu 20 Aug 2009 03:45 AM by Trask
USA #5
Glad that we can be of help :-) There's nothing wrong with being new, we were all there. People who are new but willing to learn and put in the effort to understand are usually extremely well-received, at least in my experience. It's the people who want others to write their code that tend to get the cold shoulder. ;)

Quote:
Would this therefore be one of those instance where a script would be a better means of implementing this?

It depends on what you mean and what you want. If you want a small standalone program, then often scripting languages give you far more tools to "just do it" without the hoops that C++ puts you through. If you need this to happen inside a C++ application, it might or might not be easy to embed a scripting language interpreter. Lua is extremely easy to embed (when compared to other languages), but it doesn't have as many libraries for talking to the system in various ways.

The thing is, though, that you only need to write the fundamental code once to get some process's results. I can give you 100 to 1 odds that there is a library out there that takes a system command and returns a std::string or something similar with the results -- essentially abstracting away the whole process of opening the pipe, reading from it, etc.

Quote:
I think it might be a good idea to have a poke through that /usr/include/ directory David pointed me to.

It might be worth mentioning that what you'll find in there is not necessarily intuitive, newbie-friendly or understandable. I find it rather opaque, to be honest, and find the man pages to be far more accessible. The problem with man pages is that you usually need to know what you're looking for in order to find it (catch 22!).
Australia #6
Quote:
I can give you 100 to 1 odds that there is a library out there that takes a system command and returns a std::string or something similar with the results -- essentially abstracting away the whole process of opening the pipe, reading from it, etc.


I googled for this extensively before I posted my original question on the forums, and most of the results suggested uname and popen as options... Although it could have been the case that at some point, I was clearly staring at the solution and was simply to ignorant to realise it :)

I think this is going to be my greatest frustration in regards to coding, namely the catch 22 you mentioned. In order to find out information about a function, you already need to know about the function. Gah, why do the coding gods hate me so?!? :)

In reference to what I'm after as far as this system call, as I mentioned in my original post, It was a little bit of code to throw into my fledgling mud, so I could feel as though I had made progress :) If possible, can you look at the additions I made to my mud in the first post, and let me know if they are the most efficient means of doing this?

muchas gracious senors!
Australia Forum Administrator #7
See this post about an excellent book about the STL:

http://www.gammon.com.au/forum/bbshowpost.php?id=3666

However, you may have trouble finding that in Afghanistan. I had to order it from Amazon myself - I couldn't easily find it in Melbourne either.
Australia #8
Thanks Nick,

David told me about that book in another thread. Ordering it from Amazon is definately the way to go for me, It'll take quite a while to get to me, it first goes to sydney, then gets routed to us here. As I mentioned to David, I'm reading Bruce Eckel's Thinking in CPP, and plan to order the Josuttis book as a progression.

Cheers!