Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tech Tips


Tech Tips

When Shared Data Segments Aren't Shared

There are several ways to share data between instances of DLLs. One of the methods is to use Shared Data segments that are set up in the .def file for the DLL. This method is much easier than going through all the work that memory-mapped files require. There is, however, a potentially time-consuming surprise in store for you if you do not understand one caveat about the shared memory segments.

Shared data segments are only shared between copies of a DLL loaded from the same location in the filesystem. This can be quite surprising when trying to debug a DLL with shared data segments in a system with many programs using the DLL. It is not uncommon to have the DLL loaded by parts of the system from its normal location and to also have the DLL loaded from the Debug directory in the project location. This results in two copies of the shared data segments.

To demonstrate this problem, I have written a very simple DLL that supports reading and writing a simple integer number between multiple applications. The DLL simply defines three access functions and a shared data segment with an integer. The application (included in this month's code archive) shows where the DLL is loaded from and allows the user to read and write integer values. The projects to build the DLL and application have a "Custom Build Step" that copies the target to both the bin and bin2 directories.

By running two copies of TheApp.exe from the bin directory, you can see that writing a value in one instance of the application will cause that value to be read in the other instance, just as would be expected.

Now without closing either of these instances, go to the bin2 directory and start an instance of TheApp.exe from there. Notice that when doing a read from this instance, you do not get the value written by the instances run from bin. As an additional step, you could run another instance of TheApp.exe from bin2 and see that the instances run from the same directory use the same shared memory.

Preventing Class Derivation in Visual C++ .NET

By Ehsan Akhgari

[email protected]

Here is a tip for preventing derivation from a class in C++. Suppose you have a class B, and you don't want any class to derive from this class. C++, unlike other languages such as Java, doesn't have any built-in support for this task, but this can be done using virtual inheritance. You should create and use a Lock class as this example shows:

class Lock {
             Lock() {}
             friend class B;
};

class B : private virtual Lock
{
public:
             B() {}
};

class D : public B
{
public:
             D() {}
};

int main()
{
             B b;
             D d;

             return 0;
}

B is a friend of Lock, so B::B() has access to Lock::Lock() and can initialize the virtual base class. On the other hand, D is not a friend of B, so D::D() can't initialize the virtual base class due to its inability to call Lock::Lock(). Thus, attempting to compile the aforementioned program will lead to an error. Microsoft Visual C++ .NET 2003 produces the following error messages when compiling this application:

h:\Projects\VC++.NET\test\test\test\test.cpp(17)   : error C2248: 
'Lock::Lock' : cannot access    private member declared in class 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(3)    : see
declaration of 'Lock::Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(2)    : see
declaration of 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(22)   : error C2248:
'Lock::Lock' : cannot access private member    declared in class 'Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(3)    : see
declaration of 'Lock::Lock'
h:\Projects\VC++.NET\test\test\test\test.cpp(2)   : see
declaration of 'Lock'

Do/While Macros Souped Up and Revisited (First Movement)

By Cindy Ross

[email protected]

In the June 2003 issue, John Szakmeister suggested that the macro wrapper (previously presented by Raja Venkataraman) could be improved by removing the do/while construct. But the original version with the do/while construct is better, as it can be used in any context where a C statement can be used.

For example, using the macro from the previous article, this code compiles fine:

   #define MY_ASSERT_ONE(x) do { \       if (!(x)) { \
         _asm int 3 \
      } \
      } while (0)

   main()
   {
      if ( 1 )
         MY_ASSERT_ONE(1);
      else
         return 1;
   }

but we get a syntax error if we omit the do/while construct:

   #define MY_ASSERT_ONE(x) { \       if (!(x)) { \
         _asm int 3 \
      } \
      }

   main()
   {
      if ( 1 )
         MY_ASSERT_ONE(1);
      else
         return 1;
   }

Do/While Macros Souped Up and Revisited (Second Movement)

by Petter Hesselberg

[email protected]

Regarding John Szakmeister's June 2003 Tech Tip ("A Better Macro Wrapper for Visual C++"), which was a response to Raja Venkataraman's February 2003 Tech Tip ("do/while Macros for C++").

Venkataraman's original Tech Tip starts by showing the problems associated with a simplistic ASSERT implementation such as this:

#define MY_ASSERT_ONE( x )  if ( !( x ) ) { \     _asm int 3 \
}

Using the aforementioned definition, the following code generates an "illegal else without matching if" compiler error:

if ( x )
    MY_ASSERT_ONE( y );
else
    MY_ASSERT_ONE( z );

This is fixable in two ways: Either remove the semicolons (a strange-looking and error-prone solution) or insert braces (which is a good practice in any case):

if ( x ) {     MY_ASSERT_ONE( y );
} else {
    MY_ASSERT_ONE( z );
}

Venkataraman then goes on to show the MFC/ATL solution, in which a semantically NULL do/while loop makes the semicolon required rather than forbidden:

#define MY_ASSERT_TWO( x )  do { \        if ( !( x ) ) { \
        _asm int 3 \
    } while ( 0 )

This code is, in any case, wrong because it has two opening braces but only one closing brace. The correct version looks like this:

#define MY_ASSERT_TWO( x )  do { \        if ( !( x ) ) { \
        _asm int 3 \
    } } while ( 0 )

Szakmeister's Tech Tip update then "improves" on Venkataraman's by going back to the original version. He does not discuss the semicolon problem, except to note that his version is "harmful if not used correctly" — this makes you wonder if he actually read all of the original Tech Tip.

The standard header file, assert.h, has a different solution:

#define assert(exp) \     (void)( (exp) || \
    (_assert(#exp, __FILE__, __LINE__), 0) )

This approach doesn't help if you insist on using an inline assembler, though; there's no way of making an assembly statement part of an expression. The closest you get is something like this:

int failedAssert( void ) {     __asm int 3
    return 0;
}

#define MY_ASSERT_THREE( x ) \
    (void)( (x) || failedAssert())

This works well enough — except that the interrupt occurs in failedAssert() rather than at its point of call, and you have to go manually one step up the call stack in the debugger. But inline assembly is not a necessity in Windows programming; there's DebugBreak() to the rescue:

#define MY_ASSERT_FOUR( x ) \
    (void)( (x) || DebugBreak())

But oops — DebugBreak() is a void function, and you can't have void as an operand to the || operator. Let's try the ternary conditional operator instead:

#define MY_ASSERT_FIVE( x ) \

    ((x) ? (void) 0 : DebugBreak())

The trick to safe macro programming in C/C++ is to avoid the outer braces — you need an expression rather than a statement. Consider the comma operator, also called the "sequential-evaluation operator," which lets you evaluate two or more expressions in a context where only one expression is allowed. This allows cool macros like the following, good for trashing a pointer you've just released (the purpose being to root out dangling pointer errors):

#define reset_pointer( p )  \
    ( memset( &( p ), 0xacACacAC, sizeof( p )    ), \
        assert( 4 == sizeof( p ) ) )

This is pretty cool, but can be confusing — the comma operator is easily confused with the comma that separates function or macro arguments; it is emphatically not the same thing. The following example shows how you might call a function with three parameters; the value of the second parameter passed is 3; the value of b after the function call is 1:

myFunction( a, (b = 1, b + 2), c );

If you absolutely must have inline assembly, I suspect that the do/while technique really is the safest approach — in spite of its clunkiness.

Editor's note: I hope our reader's have enjoyed this ongoing debate about do/while macros (and I'm sure we'll get the big e-mail gong if not). Kudos to Raja Venkataraman, who started the thread, and to everyone who vigorously threw in their opinion. Have an opinion of your own about any of our tips? Please send them to me at [email protected].


George Frazier is a software engineer in the System Design and Verification group at Cadence Design Systems Inc. and has been programming for Windows since 1991. He can be reached at georgefrazier@ yahoo.com.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.