|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| ||||||||||||||||||||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
#1
|
||||
|
||||
|
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 Puzzle of the Month solved by Fishmonger, superior perl programmer of the month Last edited by Scorpions4ever : September 28th, 2004 at 08:43 PM. |
|
#2
|
||||
|
||||
|
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 11:26 AM. |
|
#3
|
||||
|
||||
|
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>
using namespace std;
int main(void) {
stringstream ss;
int i = 42;
double d = 105.24;
ss << i << " " << d;
// Convert to string or char array
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>
using namespace std;
int main(void)
{
long l; int i;
char *hexstr = "12FC3";
char *octstr = "1245";
stringstream ss;
ss << hex << hexstr;
ss >> l;
ss.clear();
ss << 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>
using namespace std;
int main(void)
{
int i = 42;
char buf[50];
stringstream ss;
ss << hex << i;
ss >> buf;
ss.clear();
ss << 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 : November 13th, 2004 at 12:25 PM. |
|
#4
|
||||
|
||||
|
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>
using namespace std;
int main(void)
{
float f = 105.2345;
char buf[] = "This is a string";
cout.setf(ios::fixed);
/* Limit to 2 decimals */
cout << setprecision(2) << f << endl;
/* Print 10 chars wide, limit to 2 decimals */
cout << setw(10) << setprecision(2) << f << endl;
/* Right justify to 30 chars */
cout << 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:
cin >> setw(20) >> buf; 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 : November 20th, 2004 at 10:46 AM. |
|
#5
|
||||
|
||||
|
Place holder for Chapter 3.
|
|
#6
|
||||
|
||||
|
Place holder for Chapter 4.
|
|
#7
|
||||
|
||||
|
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 |
|
#8
|
||||
|
||||
|
I created a bit of a tutorial on performance programming at http://sol-biotech.com/code/PerformanceProgramming.html in case someone is interested.
__________________
Free code: http://sol-biotech.com/code/. Secure Programming: http://sol-biotech.com/code/SecProgFAQ.html. Performance Programming: http://sol-biotech.com/code/PerformanceProgramming.html. It is not that old programmers are any smarter or code better, it is just that they have made the same stupid mistake so many times that it is second nature to fix it. --Me, I just made it up The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man. --George Bernard Shaw |
|
#9
|
||||
|
||||
|
These are some FAQ's that I have posted a billion times:
Programming with multiple processes and Inter-Process Communication Programming Sockets (Unix based, but concepts transcend platforms) Windows Specific Socket Issues: Winsock Packet Sniffing and Injecting: Raw Sockets The Art of Unix Programming: Everything you need to know about *nix THe Unix Programming FAQ: If it's not in the one above, it's probably here Gettting strange SEGFAULTS when allocating or freeing memory? Posix Threads: Multithreading On *nix Advanced POSIX thread issues So you want to be a h4x0r? Start checking out some of these articles, and of course, all the links found in my sig
__________________
|
|
#10
|
||||
|
||||
|
win32
also wanted to share some win32 links you might find useful:
theForger's Win32 API Tutorial all win32 programmers know this one ![]() Win32 Programming - FunctionX also a fairly complete list on the basics also: Al's Win32 programming page especially his first blank window tutorial Johnnie's Win32 API Programming Tutorial |
|
#11
|
|||||
|
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:
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:
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:
Last edited by DaWei_M : November 1st, 2004 at 03:38 PM. |
|
#12
|
||
|
Pointers - A Quick View
A short pointer tutorial can be found at this link .
Last edited by DaWei_M : April 11th, 2005 at 09:37 PM. |
|
#13
|
||||
|
||||
|
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:
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. PHP Code:
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:
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 PHP Code:
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:
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:
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:
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:
whereas the programmer (because they have used the "using namespace" directive) thinks it is "obviously" equivalent to; PHP Code:
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 PHP Code:
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:
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 08:40 AM. |
|
#14
|
||||
|
||||
|
Operator Overloading Tutorial for dummies
Here is my attempt at writing a comprehensive C++ Operator Overloading Tutorial
|
|
#15
|
||||
|
||||
|
A little write-up on diagnosing and fixing buffer overflows (memory bounds violations): http://sol-biotech.com/code/BufferOverflows.html.
|
![]() |
| Viewing: Dev Shed Forums > Programming Languages > C Programming > Commonly Asked C/C++ Questions |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|
|
|
|