Personal tools
User menu

Knowledge Base/CPP/General

From Thalesians

Jump to: navigation, search

Contents

The main() function

It may seem strange, but some C++ programmers don't know the signature of the main() function. In C and C++, the function prototype of the main() function looks like one of the following:

int main(void)

or

int main(int argc, char * argv[])

The parameters argc, argument count, and argv, argument vector, respectively give the number and value of the program's command-line arguments. The names of argc and argv may be any valid identifier, but it is common convention to use these names.

In C++, main must be in the global namespace (i.e. ::main) and cannot be a (class or instance) member function.

Statically detecting the Visual Studio version

  1. #if _MSC_VER >= 1500
  2. // Visual Studio 2008 or above
  3. #elif _MSC_VER >= 1400
  4. // Visual Studio 2005
  5. #elif _MSC_VER >= 1310
  6. // Visual Studio 2003
  7. #elif _MSC_VER > 1300
  8. // Visual Studio 2002
  9. #endif

Convert an enum into an int. Convert an int into an enum

For enums, there is an implicit conversion to int:

  1. enum Quarter {FIRST=1, SECOND=2, THIRD=3, FOURTH=4};
  2. int q = FIRST;

For ints, there is an explicit conversion to enum:

  1. enum Quarter quarter;
  2. quarter = static_cast<Quarter>(2);

Testing an integer's even- or oddness

  1. if (n & 1) ...

Doubling a positive integer

  1. n <<= 1;

An algorithm for determining whether a function should be a member and/or friend

Use the following algorithm due to Herb Sutter and Andrei Alexandrescu to determine whether a function should be a member and/or friend (C++ Coding Standards: 101 Rules Guidelines and Best Practices, Item 44: Prefer writing nonmember nonfriend functions):

// If you have no choice then you have no choice; make it a member if it must be:
If the function is one of the operators =, ->, [], or (), which must be members:
        Make it a member.
// If it can be a nonmember *non*friend, or benefits from being a nonmember friend, do it:
Else if:
    a) the function needs a different type as its left-hand argument
       (as do operators >> and <<, for example);
 or b) it needs type conversions on its leftmost argument;
 or c) it can be implemented using the class's public interface alone:
        Make it a nonmember.
        If it needs to behave virtually:
            Add a virtual member function to provide the virtual behaviour,
            and implement the nonmember in terms of that.
Else
        Make it a member.

Implementing a non-const function in terms of the correpsonding const function

It is possible to implement a non-const function in terms of the corresponding const function as follows:

  1. const S & T::foo() const
  2. {
  3. // ...
  4. }
  5.  
  6. S & T::foo()
  7. {
  8. const T * cthis = this;
  9. return const_cast<T &>(cthis->foo);
  10. }

This technique, suggested by Siemel Naran, involves a const_cast.

Implementing the postfix operator++ in terms of a prefix operator++

  1. // Prefix
  2. T & operator++()
  3. {
  4. // ... Perform the increment ...
  5.  
  6. return *this;
  7. }
  8.  
  9. // Postfix
  10. const T operator++(int)
  11. {
  12. T temp = *this;
  13.  
  14. ++*this;
  15.  
  16. return temp;
  17. }

Notice that (int) is used to distinguish between the prefix and postfix versions of the operator.

Similarly for operator--:

  1. // Prefix
  2. T & operator--()
  3. {
  4. // ... Perform the increment ...
  5.  
  6. return *this;
  7. }
  8.  
  9. // Postfix
  10. const T operator--(int)
  11. {
  12. T temp = *this;
  13.  
  14. --*this;
  15.  
  16. return temp;
  17. }

Implementing operator= in terms of a (no fail) swap

The following definition of operator= in terms of a copy constructor and a no fail swap is idiomatic. swap is needed for a guaranteed commit. It must not fail. It must never throw exceptions.

  1. T & T::operator=(const T & rhs)
  2. {
  3. T temp(rhs);
  4. noFailSwap(temp);
  5. return *this;
  6. }

Implementing operator@ in terms of operator@=

Where @ is a binary operator such as +, *, etc. This is generally a very good idea, consistent with the Principle of Least Surprise.

The non-member case: operator@ and operator@= are non-members

  1. T & operator@=(T & lhs, const T & rhs)
  2. {
  3. // ...
  4.  
  5. return lhs;
  6. }
  7.  
  8. T operator@(T lhs, const T & rhs)
  9. {
  10. // Note that lhs is taken by value
  11. return lhs @= rhs;
  12. }

The member case: operator@ and operator@= are members

  1. T & operator@=(const T & rhs)
  2. {
  3. // ...
  4.  
  5. return *this;
  6. }
  7.  
  8. T & operator@(const T & rhs)
  9. {
  10. T temp(*this);
  11.  
  12. temp @= rhs;
  13.  
  14. return temp;
  15. }

Implementing operator!=, operator>, operator<=, operator>= in terms of operator== and operator<

We want to enforce consistency and avoid code repetition. Therefore we define operator== and operator<...

  1. inline bool operator==(const T & lhs, const T & rhs)
  2. {
  3. // ...
  4. }
  5.  
  6. inline bool operator<(const T & lhs, const T & rhs)
  7. {
  8. // ...
  9. }

...then implement the remaining relational operators in terms of the above, as follows:

  1. inline bool operator!=(const T & lhs, const T & rhs)
  2. {
  3. return !(lhs == rhs);
  4. }
  5.  
  6. inline bool operator>(const T & lhs, const T & rhs)
  7. {
  8. return rhs < lhs;
  9. }
  10.  
  11. inline bool operator<=(const T & lhs, const T & rhs)
  12. {
  13. return !(rhs < lhs);
  14. }
  15.  
  16. inline bool operator>=(const T & lhs, const T & rhs)
  17. {
  18. return !(lhs < rhs);
  19. }

Overloading operator<< for user-defined types

You should follow this pattern:

  1. #include <ostream>
  2.  
  3. ostream & operator<<(ostream & outputStream, const Foo & foo)
  4. {
  5. return outputStream << foo.getBar() << ", " << foo.getBaz();
  6. }

Erase-remove idiom

The erase-remove idiom is the best way to remove elements with a specific value from a contiguous-memory container (e.g. a vector, string, or queue).

  1. c.erase(remove(c.begin(), c.end(), 1666), c.end());

For lists, the remove member function is more efficient:

  1. c.remove(1666);

For associative containers one must use the erase member function:

  1. c.erase(1666);

The "swap" trick to lop off the empty (reserved) space at the end of a vector or string

  1. vector<Widget> v;
  2. string s;
  3.  
  4. // ...
  5. // Use v and s
  6. // ...
  7.  
  8. vector<Widget>(widgets).swap(v);
  9. string().swap(s);

Inserting a key-value pair into a map efficiently

  1. someMap.insert(map<T, U>::value_type(someT, someU));

Looking up an element in a map while avoiding default element insertion

If you use the subscript syntax to access a map element as follows

  1. string fooValue = someMap["foo"];

a new element will be inserted if the key "foo" is not already in the map. The corresponding value will be default-initialised. If you want to avoid this insertion, use the following:

  1. map<string, string>::iterator iter = someMap.find("foo");
  2. if (iter != someMap.end())
  3. {
  4. fooValue = iter->second;
  5. }

Inserting an element into a set if it does not already exist

If we need to insert a new element into a set provided it doesn't already exist in the set, and deal with the consequences if the element already exists, we can use the following paradigm:

  1. pair<set<string>::iterator, bool> status = someSet.insert("foo");
  2. if (! status.second)
  3. {
  4. // The element wasn't inserted as it already existed in the set
  5. // ...
  6. }

Inserting an element into a map if the key does not already exist

If we need to insert a new element into a map provided the key doesn't already exist in the map, and deal with the consequences if the key already exists, we can use the following paradigm:

  1. pair<map<string, string>::iterator, bool> status = someMap.insert(pair<string, string>("foo", "bar"));
  2. if (! status.second)
  3. {
  4. // The element wasn't inserted as the key already existed in the map
  5. // ...
  6. }

It is worth noting that if we had someMap["foo"] == "baz" before the above code was executed, someMap["foo"] would not be overwritten.

Passing arrays to functions that expect iterators

Suppose you have the following function:

  1. #include <iterator>
  2. #include <numeric>
  3.  
  4. template <typename _IterT>
  5. typename iterator_traits<_IterT>::value_type sum(_IterT from, _IterT to)
  6. {
  7. return accumulate(from, to, 0);
  8. }

You want to pass an array to it. You can do it as follows:

  1. template <typename _Data, typename _Size = size_t>
  2. _DataT sum(const _Data * data, Size N)
  3. {
  4. return sum(data, data + N);
  5. }

Adding up the element counts in a vector of vectors using std::accumulate and Boost lambda abstractions

Suppose that you have a collection of collections, e.g. a vector of vectors. You want to count all the elements in this structure (i.e. add up the sizes of the contained vectors). You can achieve this by using std::accumulate and Boost lambda abstractions:

  1. #include <iostream>
  2. #include <numeric>
  3. #include <vector>
  4.  
  5. #include <boost/lambda/bind.hpp>
  6. #include <boost/lambda/lambda.hpp>
  7.  
  8. using namespace std;
  9. using namespace boost::lambda;
  10.  
  11. void columnCountProto()
  12. {
  13. typedef vector<double> VectorOfDoubles;
  14. typedef VectorOfDoubles::size_type SizeType;
  15.  
  16. typedef vector<VectorOfDoubles> VectorOfVectorsOfDoubles;
  17.  
  18. VectorOfVectorsOfDoubles vectorOfVectors;
  19.  
  20. VectorOfDoubles v1;
  21. VectorOfDoubles v2;
  22. VectorOfDoubles v3;
  23. VectorOfDoubles v4;
  24. VectorOfDoubles v5;
  25.  
  26. v1.push_back(1.0); // 1
  27. v1.push_back(2.0); // 2
  28.  
  29. v2.push_back(3.0); // 3
  30. v2.push_back(5.0); // 4
  31. v2.push_back(7.0); // 5
  32.  
  33. v3.push_back(10.0); // 6
  34.  
  35. v5.push_back(0.0); // 7
  36.  
  37. vectorOfVectors.push_back(v1);
  38. vectorOfVectors.push_back(v2);
  39. vectorOfVectors.push_back(v3);
  40. vectorOfVectors.push_back(v4);
  41. vectorOfVectors.push_back(v5);
  42.  
  43. cout << "vectorOfVectors size: " << vectorOfVectors.size() << endl;
  44.  
  45. SizeType elementCount =
  46. accumulate(
  47. vectorOfVectors.begin(),
  48. vectorOfVectors.end(),
  49. SizeType(0),
  50. _1 + bind(&VectorOfDoubles::size, _2));
  51.  
  52. cout << elementCount << endl;
  53. }

This displays "7", as expected.

What about finding the maximum count, rather than the sum? Use the following code instead:

  1. SizeType maxElementCount = accumulate(
  2. vectorOfVectors.begin(),
  3. vectorOfVectors.end(),
  4. SizeType(0),
  5. bind(Maximum<SizeType>(),
  6. bind(&VectorOfDoubles::size, _2), _1));
  7.  
  8. cout << maxElementCount << endl;

This will display "3" (due to v2, which contains three elements).

By the way, here Maximum is defined as follows:

  1. template <typename _Type>
  2. struct Maximum : public binary_function<_Type, _Type, _Type>
  3. {
  4. _Type operator()(_Type first, _Type second) const
  5. {
  6. return (second > first) ? second : first;
  7. }
  8. };

Note that the Standard Library defines the two template functions std::min and std::max in the <algorithm> header, but Visual Studio C++ does not define these function templates as per Danny Kalev's comment. If std::max is available, you can use it instead of the Maximum above.

Remember that accumulate is defined in the header file <numeric>, not <algorithm>.

Along the same lines you can use for_each to clear the contained vectors in a vector of vectors:

  1. for_each(vectorOfVectors.begin(), vectorOfVectors.end(), bind(&VectorOfDoubles::clear, _1));

You can also reserve some space in all of them, say enough space for ten doubles:

  1. for_each(vectorOfVectors.begin(), vectorOfVectors.end(), bind(&VectorOfDoubles::reserve, _1, 10));

We can also construct a vector of iterators for the contained vectors, pointing to their first elements ("begin"):

  1. vector<VectorOfDoubles::iterator> vectorOfIterators;
  2.  
  3. transform(
  4. vectorOfVectors.begin(), vectorOfVectors.end(),
  5. back_inserter(vectorOfIterators),
  6. bind(boost::mem_fn(&VectorOfDoubles::begin), _1));

Resizing arrays dynamically at runtime

Strictly speaking, it is impossible to resize arrays at runtime. If you want a resizable array you should use something like std::vector or std::string.

However, if you are allocating arrays on the heap (and this is one of the biggest advantages of using the heap as opposed to the stack), you can reallocate them dynamically at runtime using new[]. Again, strictly speaking, you are not resizing the array. You are deleting it with delete[] and reallocating with new[].

This is useful when you don't know the required array size in advance. Suppose that you have a function

std::pair<bool, size_t> populateBuffer(char * buffer, int bufferSize);

Suppose we are dealing with C-style strings and the function also needs to write '\0'. If bufferSize is sufficient for this, it returns (true, actual size). If it isn't, it returns (false, anything). Then you can call it again with a larger buffer (up to a certain maximum buffer size, to play it safe).

In order to experiment with this, we shall define a simple deterministic

#include <cstring>
#include <string>
#include <utility>
#include <stdexcept>
 
std::pair<bool, size_t> populateBuffer(char * buffer, int bufferSize)
{
    const char * toBeWritten = "012345678901234";
 
    int toBeWrittenSize = strlen(toBeWritten);
    if (bufferSize > toBeWrittenSize)
    {
        // Strictly > because we need space for the terminating
        // null
 
        strncpy(buffer, toBeWritten, toBeWrittenSize);
 
        return std::make_pair(true, toBeWrittenSize);
    }
    else
    {
        return std::make_pair(false, 0);
    }
}

Here is how we could call this function using dynamic array reallocation at runtime:

std::string resizeArrayAtRuntime()
{
    size_t initialBufferSize = 16;
    size_t maxBufferSize = 2000;
    bool success = false;
 
    char * buffer;
 
    for (size_t bufferSize = initialBufferSize; bufferSize < maxBufferSize; bufferSize *= 2)
    {
        buffer = new char[bufferSize];
 
        std::pair<bool, size_t> populateBufferResult(populateBuffer(buffer, bufferSize));
 
        if (populateBufferResult.first)
        {
            // We are done. The text fits into the buffer
            success = true;
            break;
        }
        else
        {
            // The text does not fit into the buffer. Let us delete
            // the buffer and loop again to create a bigger one
            delete[] buffer;
        }
    }
 
    if (success)
    {
        return std::string(buffer);
    }
    else
    {
        throw std::runtime_error("The returned string is too long");
    }
}

Splitting a file pathname into the directory pathname and file basename

std::string removeTrailingSlashes(std::string filePathName)
{
    // Note that we need a copy of filePathName, so it is not being
    // passed in by constant reference
 
    size_t trailingSlashesPosition = filePathName.find_last_not_of("/\\");
 
    if (trailingSlashesPosition != std::string::npos)
    {
        filePathName.erase(trailingSlashesPosition + 1);
    }
    else
    {
        // The entire filePathName is slashes. Make it empty
        filePathName.erase(filePathName.begin(), filePathName.end());
    }
 
    return filePathName;
}
 
std::pair<std::string, std::string> splitFilePathName(const std::string & filePathName)
{
    std::string filePathNameWithoutTrailingSlashes = removeTrailingSlashes(filePathName);
 
    size_t lastSlashPosition = filePathNameWithoutTrailingSlashes.find_last_of("/\\");
 
    if (lastSlashPosition != std::string::npos)
    {
        std::string fileBaseName(filePathNameWithoutTrailingSlashes.substr(lastSlashPosition + 1));
        std::string fileDirPathName(filePathNameWithoutTrailingSlashes.substr(0, lastSlashPosition));
 
        if (fileDirPathName.empty() && !filePathNameWithoutTrailingSlashes.empty() && (filePathNameWithoutTrailingSlashes[0] == '/' || filePathNameWithoutTrailingSlashes[0] == '\\'))
        {
            return std::make_pair(filePathNameWithoutTrailingSlashes.substr(0, 1), fileBaseName);
        }
        else
        {
            return std::make_pair(fileDirPathName, fileBaseName);
        }
    }
    else
    {
        return std::make_pair(std::string(), filePathNameWithoutTrailingSlashes);
    }
}

Using dumpbin

dumpbin is a really useful utility that provides information about the format and symbols provided in executable, library, and DLL files.

In particular, /exports displays all definitions exported from an executable file or a DLL. For example,

dumpbin /exports log4cxx.dll

will display something like this:

Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file log4cxx.dll

File Type: DLL

  Section contains the following exports for log4cxx.dll

    00000000 characteristics
    4AF03BAC time date stamp Tue Nov 03 14:18:20 2009
        0.00 version
           1 ordinal base
        5869 number of functions
        5869 number of names

    ordinal hint RVA      name

          1    0 00001AC0 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@AAVObjectPtrBase@12@@Z
          2    1 000015C0 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@ABH@Z
          3    2 000016B0 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@ABV012@@Z
          4    3 00001A40 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@ABVObjectPtrBase@12@@Z
          5    4 00001640 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@PAVAction@rolling@2@@Z
          6    5 00001620 ??0?$ObjectPtrT@VAction@rolling@log4cxx@@@helpers@log4cxx@@QAE@XZ
          7    6 00002B40 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@AAVObjectPtrBase@12@@Z
          8    7 00002960 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@ABH@Z
          9    8 00002A50 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@ABV012@@Z
         10    9 00002AC0 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@ABVObjectPtrBase@12@@Z
         11    A 000029E0 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@PAVAppender@2@@Z
         12    B 000029C0 ??0?$ObjectPtrT@VAppender@log4cxx@@@helpers@log4cxx@@QAE@XZ
         13    C 00002FB0 ??0?$ObjectPtrT@VAppenderAttachable@spi@log4cxx@@@helpers@log4cxx@@QAE@AAVObjectPtrBase@12@@Z
         14    D 00002DD0 ??0?$ObjectPtrT@VAppenderAttachable@spi@log4cxx@@@helpers@log4cxx@@QAE@ABH@Z
         15    E 00002EC0 ??0?$ObjectPtrT@VAppenderAttachable@spi@log4cxx@@@helpers@log4cxx@@QAE@ABV012@@Z
...

Note that the names displayed above are mangled names but they are still readable.

LNK2001 and DLL projects

Suppose that you have a ProjectA that depends on another ProjectB. ProjectA is an executable, ProjectB is a DLL. You check Solution Properties > Common Properties > Project Dependencies to make sure that ProjectA depends on ProjectB. Indeed, the relevant tick is present.

However, when you try to build ProjectA, you see something like this:

--------------------Configuration: ProjectA - Release|Win32---------
Linking...
ProjectA.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall SomeClass1::foo(class SomeClass2 const &)" (?foo@SomeClass1@@UAEXABVSomeClass2@@@Z)
ProjectA.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall SomeClass1::bar(class SomeClass2 &,int,int)" (?bar@SomeClass1@@UAEXAAVSomeClass2@@HH@Z)
ProjectA.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall SomeClass1::baz(class SomeClass3 &)" (?baz@SomeClass1@@UAEXAAVSomeClass3@@@Z)
ProjectA.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall SomeClass1::qux(class SomeClass4 &)" (?qux@SomeClass1@@UAEXAAVSomeClass4@@@Z)
I:\dev\MySolution\Release\ProjectA.exe : fatal error LNK1120: 4 unresolved externals

Error executing link.exe (tool returned code: 1120)

ProjectA - 5 error(s), 0 warning(s)

The LNK2001 errors (and the cumulative LNK1120 error) appear because, although ProjectA depends on ProjectB, the symbols are not exported by ProjectB.

This can be changed by editing (or adding, if it doesn't exist) ProjectB.def under the ProjectB project directory with the following:

LIBRARY      "ProjectB.dll"

EXPORTS
	?foo@SomeClass1@@UAEXABVSomeClass2@@@Z
	?bar@SomeClass1@@UAEXAAVSomeClass2@@HH@Z
	?baz@SomeClass1@@UAEXAAVSomeClass3@@@Z
	?qux@SomeClass1@@UAEXAAVSomeClass4@@@Z

Note that we have listed the mangled names that appeared in the error messages.

On rebuilding the errors should disappear.

Outputting binary and hexadecimal representations of memory locations

For an explanation of the theory behind this code, see http://www.dragonwins.com/ECE1021/STATIC/LESSONS/Lesson05.htm#Printing%20Out%20the%20Bits%20in%20Multi-Btye%20Representations

#include "stdafx.h"
 
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
 
std::string getBinaryRepresentationOfSingleByte(unsigned char * address)
{
	std::ostringstream stringStream;
 
	for (unsigned char mask = 1 << (CHAR_BIT - 1); mask; mask >>= 1)
	{
		stringStream << ((*address & mask) ? '1' : '0');
	}
 
	return stringStream.str();
}
 
std::string getBinaryRepresentation(void * address, size_t numberOfBytes)
{
	std::ostringstream stringStream;
 
	unsigned char * byteAddress;
	size_t i, count;
 
	for (i = count = 0, byteAddress = reinterpret_cast<unsigned char *>(address); i < numberOfBytes; ++i, ++byteAddress)
	{
		if (i > 0)
		{
			stringStream << " ";
		}
 
		stringStream << getBinaryRepresentationOfSingleByte(byteAddress);
	}
 
	return stringStream.str();
}
 
template <typename _T>
std::string getBinaryRepresentation(_T value)
{
	return getBinaryRepresentation(&value, sizeof(value));
}
 
std::string getHexadecimalRepresentationOfSingleByte(unsigned char * address)
{
	std::ostringstream stringStream;
 
	stringStream << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << static_cast<int>(*address);
 
	return stringStream.str();
}
 
std::string getHexadecimalRepresentation(void * address, size_t numberOfBytes)
{
	std::ostringstream stringStream;
 
	unsigned char * byteAddress;
	size_t i, count;
 
	for (i = count = 0, byteAddress = reinterpret_cast<unsigned char *>(address); i < numberOfBytes; ++i, ++byteAddress)
	{
		if (i > 0)
		{
			stringStream << " ";
		}
 
		stringStream << getHexadecimalRepresentationOfSingleByte(byteAddress);
	}
 
	return stringStream.str();
}
 
template <typename _T>
std::string getHexadecimalRepresentation(_T value)
{
	return getHexadecimalRepresentation(&value, sizeof(value));
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	float f(0.0f);
	double d(0.1);
	std::string s("H");
	std::string s1("Hello");
	int n(65535);
 
	std::cout << "f" << std::endl;
	std::cout << getBinaryRepresentation(f) << std::endl;
 
	std::cout << "d" << std::endl;
	std::cout << getBinaryRepresentation(d) << std::endl;
 
	std::cout << "s" << std::endl;
	std::cout << getBinaryRepresentation(s) << std::endl;
 
	std::cout << "s1" << std::endl;
	std::cout << getBinaryRepresentation(s1) << std::endl;
 
	std::cout << "n" << std::endl;
	std::cout << getBinaryRepresentation(n) << std::endl;
 
	std::cout << "f" << std::endl;
	std::cout << getHexadecimalRepresentation(f) << std::endl;
 
	std::cout << "d" << std::endl;
	std::cout << getHexadecimalRepresentation(d) << std::endl;
 
	std::cout << "s" << std::endl;
	std::cout << getHexadecimalRepresentation(s) << std::endl;
 
	std::cout << "s1" << std::endl;
	std::cout << getHexadecimalRepresentation(s1) << std::endl;
 
	std::cout << "n" << std::endl;
	std::cout << getHexadecimalRepresentation(n) << std::endl;
 
	return 0;
}

Where is size_t defined?

According to the C++ Standard (18.1.2), a conforming implementation will offer the definition of size_t by inclusion of <cstddef>.

  • This page was last modified on 2 November 2010, at 17:14.
  • This page has been accessed 30,921 times.