Skip navigation.

Ambassador

The Royal C++ Embassy

Posts tagged with "programming"

Simple member thunk for threads

, , , ...

When you want to create a thread, CreateThread will not accept a member function. It's important to have a thread as an object, I think it's also important to keep caller provided argument to CreateThread (without introducing a tuple that holds this valuable information and casting to and from void*, managing memory, etc). In addition to traditional techniques, we can use a small thunk, too!

Read more...

Synchronization doesn't necessarily mean locking

, , , ...

... or it may mean different kind of locking.

One of the biggest problems we deal today is correct thread synchronization. Thread synchronization itself is a maze. I would like to discuss my new proposed solution to a problem; reference counting smart pointer based lock-free implementation.

Read more...

Let's obey standards

, ,

One should always assert the pre - and sometimes post - conditions in the code so that any problem that arises during debug can be caught, this hopefully saves a lot reputation of your company.

assert macro, defined in ISO 9899 standard, under Program Diagnostics section (7.2) provides an assertion mechanism, as you may already know. What it means is that:

void f(void *p)
{
    assert(p);  /* ensure p is not NULL */
    /* ... */
}


If accidentally f() is called with NULL parameter, program will stop and complain about situation, as we all expected. Usually, something like below appears:

Assertion failed on somesourcefile.c:441


Some libraries may also display a message like:

Assertion failed on somesourcefile.c:441
p

To clarify the output message, programmer may also change the code like below:
void f(void *p)
{
    assert(p != NULL);  /* ensure p is not NULL */
    /* ... */
}

In this case, assert may display:
Assertion failed on somesourcefile.c:441
p != NULL


If you had following, instead:
void f(void* p)
{
   if (p == NULL)
       _assert(TEXT("p is NULL!\r\n"), __FILE__, __LINE__);
}


Something you wouldn't expect will appear at the bottom of your build output window:
error: '_assert' undeclared identifier


Guess why...

ISO 9899 Standard (Programming Languages - C) has exactly one 'assert' and that one assert expects exactly one argument, and that is the the message to be displayed (usually, contains the expression that has been evaluated and returned false - but it's non of your business, anyway).

Do not try to access, *not just assert's (if one exists)*, but any internal or undocumented function directly. For example, do not do following on Windows (_WIN32, non-unicode configuration):

void f(void* p)
{
   if (p == NULL)
       _assert(TEXT("p is NULL!\r\n"), __FILE__, __LINE__);
}


or

#define MyNiceAssert(x)   ((!!(x)) || (_asssert(#x, __FILE__, __LINE__)))

void f(void* p)
{
    MyNiceAssert(p != NULL);
}


The "better" way, though I don't recommend, to roll your home grown assert could be something like this:

#ifdef _WIN32
// this is my land and don't you break into here
// WARNNOTE (ismailp): __FILE__ is ASCII, try following for UNICODE
// #define WIDEN(x) (L##x)
// #define WFILE    (WIDEN(__FILE__))
// #ifdef UNICODE
// #define TFILE     WFILE
// #else
// #define TFILE     __FILE__
// #endif
// MyAssertReportFunction(TEXT("Message"), TFILE, __LINE__);

void MyAssertReportFunction(LPCTSTR lpszMessage, LPCTSTR lpszFile, UINT uLine)
{
      // check input arguments
      // calculate buffer space
      // I recommend using a static MyAssert stack or heap somewhere else
      extern LPTSTR lpszBuffer;
      wsprintf(lpszBuffer, TEXT("Program aborted because pre/post ")
                             TEXT("condition has been violated.\r\n")
                             TEXT("Message: %s\r\n")
                             TEXT("File: %s\r\n")
                             TEXT("Line: %u\r\n"),
                             lpszMessage, lpszFile, uLine);
      OutputDebugString(lpszBuffer);
      // free/clean buffer used, if required
      DebugBreak();  // preferably, you can call abort() instead
}

#define MYASSERT(x)      ((!!(x)) || (MyAssertReportFunction(#x, TFILE, __LINE__)))

void CalcDate(unsigned int uYear, unsigned int uMonth,  unsigned int uDay)
{
     MYASSERT(uMonth < 13);
     /* .. */
     /* post condition */
     MYASSERT(uMonth < 13);
}
#endif // _WIN32


You can use your home grown assert if you don't like your library's assert output. You can also try following:
void CalcDate(unsigned int uYear, unsigned int uMonth,  unsigned int uDay)
{
     assert(((uMonth < 13) && TEXT("CalcDate: Pre-condition violation; Month is greater than 12.")));
     /* .. */
}


Depending on the library, as I said, it usually prints out something like below, which is more meaningful:
Assertion failed on somesourcefile.c:441
uMonth < 13 && TEXT("CalcDate: Pre-condition violation; Month is greater than 12.")


I'm not going to plot line of a horror movie to describe what could happen if you accidentally access those functions directly, but just one slightest example; _assert does not exist on Visual Studio 2005 (or may be doesn't exist with UNICODE configuration since it has _wassert), if you care about portability and future. Microsoft has never guaranteed and never guarantees that it will exist in any upcoming versions of CRT. Raymond Chen of Microsoft explains why one should not depend/rely on undocumented or internal functions:
http://blogs.msdn.com/oldnewthing/archive/2003/10/15/55296.aspx (One of my favorites)
http://blogs.msdn.com/oldnewthing/archive/2003/12/24/45779.aspx

Moral of the story;
Do
not
use
undocumented
or
internal
functions
directly,
period
.
Download Opera, the fastest and most secure browser
November 2009
S M T W T F S
October 2009December 2009
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30