 |
|
|
|
|
|

Dev Shed Forums Sponsor:
|
|
|

August 30th, 2004, 03:44 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
Commonly Asked C/C++ Questions
Here are some answers to commonly asked C/C++ questions on the forum. If you are new to the forum, please read this thread as your question may already be answered here. This guide is divided into many sections:
0. Frequently Asked Newbie Questions (how do I pause output, compile my program etc.)
1. Converting types
2. Formatting Output
3. String manipulation (copy, concatenate, replace etc.)
4. File Manipulation (File size, dir contents, remove files etc.)
5. Secure Programming Practices for Newbies.
This guide is a work in progress, so feel free to PM me with your suggestions.
CREDITS
---------------
(in order of how they replied to the original thread)
DaWei_M
Deltron74
grumpy
movEAX_444
mitakeet
NetBSD
User Name
infamous41md
__________________
Up the Irons
What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
"Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
Down with Sharon Osbourne
Last edited by Scorpions4ever : September 28th, 2004 at 07:43 PM.
|

August 30th, 2004, 03:45 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
0. Frequently Asked Newbie Questions (FNGFAQ)
0. Frequently Asked Newbie Questions (FNGFAQ)
----------------------------------------------
0.1. Where can I get a C or C++ compiler?
Depends on your operating system. See the following links:
http://www.compilers.net/Dir/Free/Compilers/CCpp.htm
http://www.bloodshed.net/compilers/index.html
http://www.openwatcom.org/ (Formerly Watcom/Sybase compiler)
http://www.digitalmars.com/ (Formerly Symantec/Zortech compiler)
http://community.borland.com/museum/ (Ancient Borland compilers)
http://msdn.microsoft.com/visualc/vctoolkit2003/ (Free Visual C++ 2003 Toolkit)
http://www.borland.com/products/dow...d_cbuilder.html (Borland C++ Builder Trial Version download)
In general, people on this forum generally use the following:
On Unix-like OS (Linux, FreeBSD, OpenBSD, NetBSD, Darwin etc.):
gcc
tendra (this is a relatively unknown compiler though  ).
On Windows:
Bloodshed Dev C++ (which uses gcc as the backend)
Visual C++
Borland C++ and Borland C++ Builder
0.2 How do I compile my program?
On unix-like systems:
gcc -o exename myfile.c
This will compile myfile.c to produce an executable file called exename. You can then run exename by typing ./exename
On Windows systems, different compilers have different keys to compile a program.
Bloodshed/Dev C++: Ctrl-F9 compiles, Ctrl-F10 executes.
Visual C++: F7 compiles, F5 executes.
Borland C++ Builder: Ctrl-F9 compiles, F9 executes.
Turbo-C: F9 compiles, Ctrl-F9 executes.
0.3 I cannot see my C compiler output. The window is closing too quickly for me.
This is a common question that many newbie programmers on Windows have. See http://forums.devshed.com/t157960/s.html for many solutions.
0.4 What are some handy C/C++ links?
http://www.eskimo.com/~scs/C-faq/top.html
http://www.parashift.com/c++-faq-lite/
0.5 Why does my scanf/fscanf/sscanf stop working?
Most C input is provided in a stream. That is, it is a series of characters made available one at a time. The scanf() function family are format-sensitive functions; they not only collect the characters for you, but attempt to convert them to a type (such as an integer) that you specify. They have great difficulty converting ZyGH4 to a meaningful number so they fail. The conversion attempt is governed by format specifiers that YOU provide. Since these may not match the input actually encountered, the family returns a value indicating the number of items successfully scanned AND assigned. If this value is zero, you have nothing. If this value is EOF, there was an end-of-file or other error. If you don't examine the return, how will you know? If an error occurs it will not be automatically cleared. Operations on the stream will continue to return an error until clearerr(), fseek(), fsetpos(), or rewind() is called. This means that a loop that is designed to pause for input will loop indefinitely.
The characters that f/s/scanf attempt to convert as one value are all the characters up to the first whitespace character (space, tab, newline) or up to the specified field width, or up to the first character that cannot be converted. (Note: The [ and c format directives are not whitespace delimited, but we won't consider them for the explanation here). If a character conflicts with the format specification, the function terminates and the character is left in the stream as if it had not been read. You probably will not expect it to be there to serve as input for your next call, so your input will not behave as you expect.
Example of proper usage:
int status;
status = scanf ("%s%d\n", name, &number);
Check the value of 'status' after the scanf() call. If it is not what you expect (two, in this case), you didn't get all your fields. If it is EOF, your stream is broken and will remain so until you clear the error.
0.6 Why does getline() not work correctly with Visual C++ (VC++)? Why do I have to type Enter twice for getline to process my input line?
If you're reading this, you've probably noticed that getline() is not functioning the way your book says it should -- you need to hit <enter> twice for the program to read your input. For example:
Code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cout<<"Enter a name:\n";
getline(cin, name);
cout<<name<<endl;
return 0;
}
This is because there's a known bug in Visual C++'s implementation of getline() (in the VC++ 6.0 Standard/Professional/Enterprise editions only, .NET has the fix). See the fix here: http://support.microsoft.com/defaul...B;EN-US;q240015
Further reading: http://forums.devshed.com/showthread.php?threadid=51971
Last edited by Scorpions4ever : December 9th, 2004 at 10:26 AM.
|

August 30th, 2004, 03:46 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
1. FACQ - Frequently Asked Conversion Questions
1. FACQ - Frequently Asked Conversion Questions
=====================================
1.1 How do I convert a char array to integer/double/long type?
Use the atoi(), atof() or atol() functions. Also see question 1.3 below.
Code:
#include <stdlib.h>
int main(void)
{
char *buf1 = "42";
char buf2[] = "69.00";
int i;
double d;
long l;
i = atoi(buf1);
l = atol(buf1);
d = atof(buf2);
return 0;
}
1.2. How do I convert an integer/float/double/long type variable to a char array?
Use sprintf(). Many books/websites tell you to use itoa(), itol(), itof() etc., but these functions are compiler specific and are therefore non-portable. sprintf() is definitely the way to go.
Code:
#include <stdio.h>
int main(void)
{
int i = 42;
float f = 69.0;
double d = 105.24;
long l = 23;
char buf[50];
sprintf(buf, "%d", i);
sprintf(buf, "%f", f);
sprintf(buf, "%f", d);
sprintf(buf, "%ld", l);
sprintf(buf, "%d %f %ld", i, f, l);
return 0;
}
C++ users may also use the stringstream or ostringstream class (the deprecated form was strstream class)
Code:
#include <sstream>
#include <string>
int main(void) {
std::stringstream ss;
int i = 42;
double d = 105.24;
ss << i << " " << d;
// Convert to string or char array
std::string s = ss.str();
char buf[50];
sprintf(buf, ss.str().c_str());
}
1.3. How do I convert a hex/octal/any-other-base value to a number?
Use strtol() or sscanf().
Code:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
long l; int i;
unsigned int ui;
char *hexstr = "12FC3";
char *octstr = "1245";
char *binarystr = "1101";
l = strtol(hexstr, NULL, 16);
l = strtol(octstr, NULL, 8);
l = strtol(binarystr, NULL, 2);
sscanf("12", "%d", &i);
sscanf("14", "%ld", &l);
sscanf(hexstr, "%x", &ui);
sscanf(hexstr, "%o", &ui);
return 0;
}
C++ users may want to use stringstream instead (strstream is deprecated).
Code:
#include <sstream>
#include <string>
int main(void)
{
long l; int i;
char *hexstr = "12FC3";
char *octstr = "1245";
std::stringstream ss;
ss << std::hex << hexstr;
ss >> l;
ss.clear();
ss << std::oct << octstr;
ss >> i;
return 0;
}
1.4. How do I convert an integer to hexadecimal (hex) /octal (oct)?
Use sprintf().
Code:
#include <stdio.h>
int main(void)
{
int i = 42;
char buf[50];
sprintf(buf, "%x", i); /* convert to hex */
sprintf(buf, "%o", i); /* convert to octal */
return 0;
}
C++ users may want to use stringstream instead (strstream is deprecated).
Code:
#include <sstream>
#include <string>
int main(void)
{
int i = 42;
char buf[50];
std::stringstream ss;
ss << std::hex << i;
ss >> buf;
ss.clear();
ss << std::oct << i;
ss >> buf;
return 0;
}
1.5 What's the equivalent of perl/pascal/vb/php's chr() and ord() functions in C/C++?
There aren't any functions like this in C or C++ and they aren't needed anyway. You can get a char's ASCII value by simply assigning it to an integer variable.
Code:
char ch;
int i;
ch = 'A';
i = ch; /* Assigns the ASCII value of 'A' (i.e.) 65 to i */
printf("%d\n", i); /* Prints 65 */
To do the reverse (i.e.) what the ord() function does, simply assign an integer to a char variable. You'll need to force a cast to avoid compiler warnings for some compilers though
Code:
int i;
char ch;
i = 65;
ch = (char) i;
/* some compilers don't warn you if you do:
ch = i;
and some will, hence the explicit cast to char type. The cast
assures the compilers that warn you, that you know what you're doing. */
printf("%c\n", ch); /* prints 'A' */
Since characters and integers are treated somewhat alike in C/C++, you can perform arithmetic operations and comparision operations with char variables, just as you do with integer variables. For instance:
Code:
char ConvertToUpperCase(char ch) {
if (ch >= 'a' && ch <= 'z')
ch = ch - 'a' + 'A';
return ch;
}
The above code takes a variable as input and checks if it is a lowercase letter by comparing its ASCII value to see if it is between the ASCII for 'a' and 'z'. If so, it subtracts the ASCII value of 'a' and adds the ASCII value of 'A', thereby converting it to an uppercase ASCII value.
Last edited by Scorpions4ever : October 4th, 2010 at 11:01 AM.
|

August 30th, 2004, 03:48 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
2. Frequently Asked Print Formatting Questions
2. FREQUENTLY ASKED PRINT FORMATTING QUESTIONS
==========================================
2.1 How do I print an integer/char/char array/float/double/long/long double/long long?
Use appropriate formatting strings (%d, %ld, %f, %Lf, %lld) with your printf statements.
Code:
#include <stdio.h>
int main(void)
{
int i = 23; long l = 42;
float f = 105.23; double d = 69.05;
long double ld = 55.23; long long ll = 92;
char c='a'; char s[] = "This is a string";
printf("int = %d\nlong = %ld\n", i, l);
printf("float = %f\ndouble = %fd\n", f, d);
printf("long double = %Lf\nlong long = %lld\n", ld, ll);
printf("char = "%c\nString=%s\n", c, s);
return 0;
}
C++ users can use cout and not worry about the format string types  .
2.2 How do I limit the precision/length of floating point, double numbers or char strings?
Use the format strings to specify precision.
Code:
#include <stdio.h>
int main(void)
{
float f = 105.2345;
char buf[] = "This is a string";
/* Limit to 2 decimals */
printf("float = %.2f\n", f);
/* Print 10 chars wide, limit to 2 decimals */
printf("float = %10.2f\n", f);
/* Print 10 chars wide, limit to 2 decimals and left-justify */
printf("float = %-10.2f\n", f);
/* Limit to 10 characters */
printf("%.10s\n", buf);
return 0;
}
C++ users may use the iomanip functions setprecision() and setw() to do this.
Code:
#include <iostream>
#include <iomanip>
int main(void)
{
float f = 105.2345;
char buf[] = "This is a string";
std::cout.setf(std::ios::fixed);
/* Limit to 2 decimals */
std::cout << std::setprecision(2) << f << endl;
/* Print 10 chars wide, limit to 2 decimals */
std::cout << std::setw(10) << std::setprecision(2) << f << endl;
/* Right justify to 30 chars */
std::cout << std::setw(30) << buf << endl;
return 0;
}
2.3 How do I control how many chars are read in a string when using scanf()?
You can use the a format specifier in the scanf() function.
Code:
char buf[25];
scanf("%20s", buf);
The above code limits the length of the characters that will be read by scanf() to 20 characters maximum (note that the buffer can hold 25 characters though!)
C++ Users can use either setw() or cin.get()
Code:
std::cin >> std::setw(20) >> buf;
std::cin.get(buf, 20);
Either statement does the same thing. Note that the above code will read 19 characters max and put \0 for the 20th character.
2.4 How do I print a triangle, hourglass, sinewave or upside-down triangle?
See this thread: http://forums.devshed.com/t137892/s.html and search this forum for more examples.
Last edited by Scorpions4ever : October 4th, 2010 at 11:03 AM.
|

September 28th, 2004, 07:38 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
Place holder for Chapter 3.
|

September 28th, 2004, 07:38 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
Place holder for Chapter 4.
|

September 28th, 2004, 07:43 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
5. Secure Programming Practices for Newbies
--------------------------------------------
Here's a FAQ put together by our very own mitakeet, with feedback from infamous41md. It covers several security issues, not just with C/C++ programming, but general practices to ensure the security of your applications. This article is a work in progress, so check back often:
http://sol-biotech.com/code/SecProgFAQ.html
|

October 9th, 2004, 01:36 PM
|
 |
I'm Baaaaaaack!
|
|
Join Date: Jul 2003
Location: Maryland
|
|
|

October 28th, 2004, 10:27 PM
|
 |
not a fan of fascism (n00b)
|
|
Join Date: Feb 2003
Location: ct
|
|
|

October 30th, 2004, 10:06 AM
|
 |
Last Day: May 29, 2005
|
|
Join Date: Sep 2004
Location: elemental sphere
Posts: 742
 
Time spent in forums: 5 Days 7 h 20 m 20 sec
Reputation Power: 9
|
|
|
win32
|

November 1st, 2004, 02:34 PM
|
 |
Renaissance Redneck
|
|
Join Date: Jan 2004
Location: Central New York. Texan via Arizona, out of his element!
|
|
|
A few ways to open and use files
HOW TO OPEN AND USE A FILE
Methods for opening files for reading and writing might be classified as C++, C stream, and C low-level methods. There are numerous variations, particularly with C++ streams; this post can in no way be considered exhaustive. CHECK YOUR DOCUMENTATION.
A NOTE ABOUT MODE
Unix/Linux have only one mode for file operations: binary. Windows has a text mode which is, unfortunately, the default. In text mode, content beyond what you supply is written to the file; it is stripped when you read the file. This makes the use of
random access (seek, tell, etc.), problematic. Even worse, a 'soft' EOF, a special character, is written. This indicator is NOT MOVED if you do an append, so appended data is not reachable unless you reset the EOF indication. Consequently, I recommend always using binary mode. With 'fopen,' you can specify a read or write or other mode as "rb", "wb", etc. Unix/Linux will accept and ignore the 'b', so you can use it portably. You can also set the default mode in Windows with the global variable, _fmode.
C++ USING FSTREAM
VC++ 6.0, Windows XP
Include iostream, fstream, and string for the following examples.
FSTREAM
OPENING FOR WRITE
Code:
// Example variables
string sFileName = "test.txt";
string sContents = "File data\n";
string sToken;
char lineBuffer [256];
int nCount = 0;
// Construct an fstream object and attempt to open
// for output
fstream ooFile;
ooFile.open (sFileName.c_str (), ios::binary | ios::out);
// Test for success
if (!ooFile.is_open ()) return badHappenstance ("Couldn't open file for writing");
// Write example
ooFile << sContents;
// Test the write for success
if (!ooFile.good ()) return badHappenstance ("Write failed");
// Close the file. Note that the file will be closed automatically when
// the object is destroyed (goes out of scope).
ooFile.close ();
OPENING FOR READ
Code:
// Open it for input
ooFile.open (sFileName.c_str (), ios::binary | ios::in);
if (!ooFile.is_open ()) return badHappenstance ("Couldn't open file for reading");
// Read tokens until end of file or error
while (ooFile.good ())
{
ooFile >> sToken;
cout << "Token " << ++nCount << ": ";
if (sToken.size ()) cout << sToken; else cout << "(null token)";
cout << endl;
}
// Check some status for grins
if (ooFile.eof ()) cout << "Reached EOF" << endl;
else if (ooFile.fail ()) return badHappenstance ("Read failed for some reason");
// Alternatively, read entire line
ooFile.getline (lineBuffer, sizeof (lineBuffer));
// Always the status
if (!(ooFile.good () || ooFile.eof ()))
return badHappenstance ("Failure reading line");
cout << "This is the line: " << lineBuffer << endl;
A SEEK EXAMPLE
Code:
// Position to beginning after clearing EOF or fail bits
ooFile.clear ();
ooFile.seekg (0, ios::beg);
if (!ooFile.good ()) return badHappenstance ("Seek failed");
ooFile.close ();
Example output:
Quote:
Token 1: File
Token 2: data
Token 3: (null token)
Reached EOF
This is the line: File data |
C USING FOPEN
VC++ 6.0, Windows XP
Include stdio.h for this method.
OPENING FOR WRITE
Code:
// Example variables
FILE *ooFile;
char sFileName [] = "test.txt";
char sContents [] = "File data\n";
char sToken [32];
char lineBuffer [256];
int nCount = 0;
int status;
// Attempt to open file for output
ooFile = fopen (sFileName, "wb");
// Test for success
if (!ooFile) return badHappenstance ("Couldn't open file for writing");
// Write the contents
status = fputs (sContents, ooFile);
// Test for success
if (status == EOF) return badHappenstance ("Write failed");
// Close the file
fclose (ooFile);
OPENING FOR INPUT
Code:
ooFile = fopen (sFileName, "rb");
if (!ooFile) return badHappenstance ("Couldn't open file for reading");
// Read tokens until end of file or error -- one method: fscanf
// fscanf consumes whitespace, unlike some C++ methods
// so there won't be a null token at the end.
while (1)
{
if (fscanf (ooFile, "%s", sToken) != 1)
{
if (feof (ooFile))
{
printf ("Reached EOF\n");
break;
}
else return badHappenstance ("Failed to read token");
}
printf ("Token %d: %s\n", ++nCount, sToken);
}
// REPOSITIONING EXAMPLE
rewind (ooFile);
// Read a line all in one swell foop
// We'll either fill the buffer or have a newline
// at the end of the buffer, or both. If you don't
// want the newline:
//
// index = strlen (lineBuffer) - 1;
// if (lineBuffer [index] == '\n')
// lineBuffer [index] = '\0';"
//
if (fgets (lineBuffer, sizeof (lineBuffer), ooFile) == NULL)
// Always the status; EOF is okay, error is not
if (ferror (ooFile)) return badHappenstance ("Failed to read line");
printf ("This is the line: %s", lineBuffer);
fclose (ooFile);
Example output:
Quote:
Token 1: File
Token 2: data
Reached EOF
This is the line: File data |
C USING LOW LEVEL _open
As far as I'm concerned, low level file operations are only good for reading large amounts of binary data, and are not necessary for that. One is far better off using the higher level functions.
VC++ 6.0, Windows XP
Include stdio.h, io.h, fcntl.h, sys\stat.h, ctype.h, and string.h for the following example.
OPENING FOR READ/WRITE
Code:
typedef int fileHandle;
extern int errno;
// Example variables
fileHandle ooFile;
char sFileName [] = "test.txt";
char sContents [] = "File data\n";
char sToken [32];
char sTrash [32];
char lineBuffer [256];
int nChars, nTokens;
int status;
// Attempt to open file for input/output
ooFile = _open ("test.txt", _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY, _S_IWRITE);
// Test for success
if (ooFile == EOF) return badHappenstance (strerror (errno));
WRITING
Code:
// Write the contents
status = _write (ooFile, sContents, strlen (sContents));
// Test for success
if (status == EOF) return badHappenstance ("Write failed");
SEEK AND READ OPERATION -- Far more complex than higher level methods
Code:
// Return to the beginning for input
if (_lseek (ooFile, 0, SEEK_SET) == -1L)
return badHappenstance ("Seek to beginning failed");
// Read tokens until end of file or error
nTokens = 0;
while (1)
{
// Skip any whitespace
while (status = _read (ooFile, sTrash, 1) == 1)
if (!isspace (sTrash [0])) break;
// Check for EOF or failure
if (status < 0) return badHappenstance ("Failure to read data");
else if (status == 0) break;
sToken [0] = sTrash [0];
for (nChars = 1; nChars < sizeof (sToken) - 1; nChars++)
{
status = _read (ooFile, &sToken [nChars], 1);
// Check for EOF or failure
if (status < 0) return badHappenstance ("Failure in reading data");
else if ((status == 0) || (isspace (sToken [nChars])))
{
sToken [nChars] = '\0';
break;
}
}
// The token could be too long...
if (nChars >= sizeof (sToken) - 1)
{
sTrash [0] = ' ';
// Skip any remaining non-whitespace characters
while (status = _read (ooFile, sTrash, 1) == 1)
if (!isspace (sTrash [0])) break;
// Check for EOF or failure
if (status < 0) return badHappenstance ("Failure in reading data");
else if (status == 0) break;
}
// Or we could have completed the token
if (strlen (sToken) > 0) printf ("Token %d: %s\n", ++nTokens, sToken);
}
printf ("End of file\n");
// Reposition to beginning
if (_lseek (ooFile, 0, SEEK_SET) == -1L)
return badHappenstance ("Seek to beginning failed");
// Read one buffer's worth
status = _read (ooFile, lineBuffer, sizeof (lineBuffer) - 1);
if (status > 0)
lineBuffer [status] = '\0';
printf ("This is the line: %s", lineBuffer);
_close (ooFile);
return 0;
}
Example output:
Quote:
Token 1: File
Token 2: data
End of file
This is the line: File data |
__________________
Functionality rules and clarity matters; if you can work a little elegance in there, you're stylin'.
If you can't spell "u", "ur", and "ne1", why would I hire you? 300 baud modem? Forget I mentioned it.
DaWei on Pointers Politically Incorrect.
Last edited by DaWei_M : November 1st, 2004 at 02:38 PM.
|

December 29th, 2004, 11:47 AM
|
 |
Renaissance Redneck
|
|
Join Date: Jan 2004
Location: Central New York. Texan via Arizona, out of his element!
|
|
|
Pointers - A Quick View
A short pointer tutorial can be found at this link .
Last edited by DaWei_M : April 11th, 2005 at 08:37 PM.
|

January 28th, 2005, 08:24 PM
|
 |
Left due to despotic ad-min
|
|
Join Date: Jun 2003
Posts: 1,044
  
Time spent in forums: 2 Days 53 m 47 sec
Reputation Power: 12
|
|
|
Namespaces and the "using" directive
This is a repost (with additions/corrections) of my response to a query about namespaces in the main forum. Some others suggested I add this to the FAQ, so....
Namespaces and their close ally, the using directive, have a dubious distinction of being features of the C++ language that most programmers employ, while also being on the list of features that are most often misunderstood and misused.
The following is a partial (and probably imperfect) attempt to describe what namespaces are in C++, and some forms of the "using" directive. Over time I may edit this post to make the discussion more complete (eg discuss the various gotcha's that arise from misunderstanding how namespaces work) or make corrections. If people pick up errors, or want to suggest additional material to include here, send me a private message.
In simple terms, namespaces are a means of grouping the names of things..... by "things" I include type declarations, function names, type definitions, object names, etc etc. Consider an application that is built using several libraries that were written independently by other developers. In this case, the odds of two libraries using the same name for different things increases substantially. For example, a library concerned with multithreading might provide a class named Thread, which is responsible for creating an operating system thread and executing some function in the context of that thread. Now, let's consider an application that will do things multithreaded, but the actual purpose of that application is to control a set of sewing machines. The application therefore needs to use another library that also happens to define a class called Thread. Without namespaces, it would not be (easily) possible to use both libraries in the same application [there are techniques, but they are pretty arcane, particularly if our application developer cannot access source code for one or both libraries]. This is formally (according to the C++ standard) a violation of the "one definition rule" --- there should only be one definition of class Thread, not two. In practice, one might sometimes get lucky (eg our two hypothetical Thread classes might have all member functions with different names), but if both classes have a member function of the same name (eg both declare a non-static function of the form "void Initialise()") it is tricky even convincing the compiler and linker to build the application, let alone being able to run it.
The purpose of namespaces is to reduce the odds that logically unrelated things wind up with exactly the same name. In our example, the developer of the multithreading library might define a namespace called Multithreading, while the developer of the other library may define a namespace named Cotton, viz.
PHP Code:
// in the header files and implementation of operating system theads ....
namespace Multithreading
{
// all the definitions and declarations related to operating system threads
}
// ... and in the header related to doing stuff with cotton ...
namespace Cotton
{
// all the definitions and declarations related manipulating cotton threads
}
The actual names of the namespaces don't matter, as long as they are different. The C++ standard defines a namespace named std, into which everything in the standard library exists (and application developers are not allowed to insert things into that namespace). Third party library developers pick the names of namespaces in various ways to reduce the odds of clashing with other libraries (eg by embedding their company name in the namespace name). Technically, this doesn't eliminate the possibility of duplicating names (eg two different library developers might happen to choose exactly the same name for their namespace), but the odds of it happening are substantially reduced.
One nice thing about namespaces is they can be nested. For example, the Multithreading namespace I'm using in this example might include, within it, another namespace named Synchronisation which defines things related to mutexes and critical sections. Another feature is that everything within a class (or struct) definition appears in a namespace of the same name as the class. So the fully qualified (or fully scoped) name of a class related to critical sections might be something like "Multithreading::Synchronisation::CriticalSection", meaning that CriticalSection is a name within a namespace called Synchronisation, which is in turn within a namespace called Multithreading.
This is all fine and dandy, but having to use the fully scoped name of an object or type gets inconvenient. For example, if we use the standard string class, every time we use a string, we have to name it std::string. Programmers are lazy souls (even worse than mathematicians, but mathematicians are taught to be deliberately lazy), so they whinge about having to do this in code where they don't use any other string class. This results in various forms of the "using" keyword.
The most common one seen (and the one which I would argue should be used less) is.
takes everything that is declared or defined in namespace std, and allows them to be used without explicitly prefixing them with "std::".
One (of many) problems with doing this is shown in this example;
PHP Code:
#include <string>
// from another header ...
namespace Foo
{
class string
{
// whatever
};
}
// now try to use our strings
using namespace std;
using namespace Foo;
int main()
{
string x; // compiler complaint due to ambiguity
// (not possible to decide what string to use).
}
The string declaration within main() potentially resolves to either std::string or Foo::string. And there is no reason for the compiler to prefer one over the other....
This is one reason (of several) that "using namespace" directives are often frowned upon.....they can give unintended effects such as code that can't be compiled because it is ambiguous. Putting a "using namespace" directive into any header file is bad practice, because it means every source file that #include's that header file has the chance of encountering this sort of ambiguity. And the only fix for such ambiguity is for the programmer to only use fully scoped names (eg "std::string" rather than "string" in the above example).
Another form of a using directive is
which basically allows definitions associated with std::string to be used, without pulling everything in namespace std along for the ride.
Another use of the using keyword is to get around the "hiding rule", which is designed (deliberately, for reasons I won't go into here) to catch programmers out who do this;
PHP Code:
class Base
{
public:
void Foo(int);
};
class Derived: public Base
{
public:
void Foo(double);
};
int main()
{
Derived x;
x.Foo(1); // will cause a compiler error, as Foo(int) is hidden
}
If the intent in this example is for class Derived to supply both a Foo(int) and a Foo(double), the definition of Derived may be changed to....
PHP Code:
class Derived: public Base
{
public:
using Base::Foo;
void Foo(double);
};
Note that, in this case, the "using" directive is local to class Derived.
A common misunderstanding of the using directive and namespaces is shown in the following example;
PHP Code:
#include <iostream>
using namespace std;
class Foo
{
// various other details
friend ostream & operator<<(ostream &, const Foo &);
};
int main()
{
Foo x;
cout << x;
}
Most novices believe that the above will work, and output the object x to the standard stream std::cout. Even worse, some text books (which I won't name) encourage that belief. The result, however, is usually a compile time error. Worse still, some compilers also get it wrong, and don't complain---leaving a user mystified about why x is not output to standard output.
This example is problematical because the "using namespace" directive does not interact with the friend declaration (except with some buggy compilers) in the "obvious" way. The friend declaration is actually equivalent to
PHP Code:
friend ::ostream &operator<<(::ostream &, const Foo &);
whereas the programmer (because they have used the "using namespace" directive) thinks it is "obviously" equivalent to;
PHP Code:
friend std::ostream &operator<<(std::ostream &, const Foo &);
The first form has actually (implicitly) declared a type named ostream in the (unnamed) global namespace, and then declared an operator<<() that works with that implicitly declared type. The problem is, the type ::ostream is completely distinct from std::ostream. When we come to use it, in the line
the compiler realises that cout is actually std::cout (thanks to the using directive) and then looks for an implementation of the corresponding operator<<() that works with a std::ostream on the left hand side and a Foo on the right. Our function "::ostream &operator<<(::ostream &, const Foo &)" does not satisfy that search, so a compile time error occurs.
In practice, to make the above example work, I would suggest never employing the "using namespace" directive in a header file or before any class declaration. Instead, I would do this;
PHP Code:
#include <iostream>
// the following may be in a header file
class Foo
{
// various other details
friend std::ostream & operator<<(std::ostream &, const Foo &);
};
// OK, in our executing code we want to be lazy
using namespace std;
int main()
{
Foo x;
cout << x;
}
This form also (thankfully) works as intended, even with compilers out there that handle the first form incorrectly.
__________________
It is only our bad temper that we put down to being tired or worried or hungry; we put our good temper down to ourselves."
-- C.S. Lewis
I like long walks, especially when they're taken by people who annoy me.
--Fred Allen
Last edited by grumpy : May 21st, 2005 at 07:40 AM.
|

March 22nd, 2005, 06:00 PM
|
 |
Banned ;)
|
|
Join Date: Nov 2001
Location: Woodland Hills, Los Angeles County, California, USA
|
|
|
Operator Overloading Tutorial for dummies
|

March 30th, 2005, 06:56 AM
|
 |
I'm Baaaaaaack!
|
|
Join Date: Jul 2003
Location: Maryland
|
|
|
Developer Shed Advertisers and Affiliates
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|