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

We Have Mail


March 1998/New Products


Letters to the editor may be sent via email to [email protected], or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.


P.J.,

Your Forum for CUJ November 1997 brought to mind a prolonged discussion at my former employer. I was with a (now all but gone) mainframe company for 27 years. The discussion was professional instructors vs. techies who were currently active with a particular product (hard or soft). Not all techies could teach and fewer still could teach well. But training mostly stayed with pro instructors.

When all was said and done, customers seemed to stand on their own better after one of the good techies had done the teaching. That is a very subjective judgement. But the pro instructors came to the techies for hard questions — knowing that experience had the answer.

I have good friends who are pro instructors even yet. They seem to do best when the subject is one in which they have immersed themselves most deeply — on a practical, working basis. But I frankly do not want to take courses from them in certain areas.

Thanks for your good work & stimulating magazine.

Phil Caldwell
Dallas, Texas

My father was a master of several crafts. He was happy to pass on his hard-won knowledge to others, but he was always quick to say he was just an instructor, not a teacher. The latter has skills in conveying knowledge quite separate from the skills being conveyed. Our field needs both knowledgable instructors and skilled teachers — and the wisdom to know the difference. — pjp


Editor,
John L. Gammel,

The problem with accessing more than 32 MB physical memory is not the compiler, but is the restricted version of the DOS/4G DOS Extender bundled with the compiler. Even the DOS/4GW pro is not the full version, comes nearly without any documentation, and you would have several levels of upgrades and pricing before you. Instead I recommend one of the following DOS Extenders:

1) Shareware PMODE/W by Charles Scheffold and Thomas Pytel. PMW133.ZIP or newer is downloadable at the following sites:

http://www.dorsai.org/~daredevi/pmw
http://www.di.net/pmw
ftp://ftp.cdrom.com/pub/demos/incoming/code
ftp://ftp.cdrom.com/pub/demos/code/pmode

It doesn't support swap files, but for the remaining areas there are more features and better documentation, including exe file compression capability.

In an existing exe file you can replace and/or compress the current extender by the PMODE/W extender by a simple command-line call. Alternatively you can add a line to the linker control file and let Watcom C/C++ use the PMODE/W extender automatically.

2) Commercial Causeway by Michael Devore Information is available at www.devoresoftware.com. It has even more features than PMODE/W and the full version is cheaper. But the paging unit of the processor remains active, even if the swap file is disabled. However the paging unit is active as soon as EMM386.EXE is loaded, and EMM386.EXE itself seems to have a bigger impact on response time than the paging unit of the processor.

All programs running under a DOS Extender use the DPMI interface to get access to special extender services, e.g., mapping physical memory, and switching between real mode and protected mode while interrupt handling. The DPMI interface is a de facto standard and documentation should be available at several places on the internet.

Helmut Tischer
boards AG, Germany
[email protected]


Dear CUJ,

In "We Have Mail" in the December 1997 edition of CUJ, John L. Gammel writes:

"Here are questions more properly addressed to PowerSoft (formerly Watcom) or Tenberry (formerly Rational Systems). I've had no success getting satisfactory answers from them, so I turn to you. I write and run C++ codes requiring much memory to store large arrays and requiring much running time. My 200 Mhz Pentium Pro computer has 128MB of RAM. My problem is that I do not know of a C++ compiler which allows access to 128 MB of (physical, not virtual) RAM, and virtual memory managers slow down the calculations too much."

I'm always amazed when I see people who turn to commercial products when there is free software that lets them do what they need, with little or no cost and with much better technical support. In the case in point, there is a free port of the GNU C/C++ compiler to MS-DOS and MS-Windows called DJGPP. It generates 32-bit extended DOS programs that run on top of DOS or Windows using the so-called DPMI (an acronym for DOS Protected Mode Interface) services. MS-Windows have DPMI services built into them, and DJGPP comes with a free DPMI server, called CWSDPMI, for running the programs on plain DOS.

MS-Windows and most of other commercial DPMI servers (such as QDPMI and 386Max) will let you use at least 64 MB of physical RAM. So even with the simplest setup — say, on Windows 95 — you already get twice as much as with John's best alternative that he reported in his letter.

However, CWSDPMI supports up to 256 MB of physical RAM when it runs on top of a memory manager that supports more than 64 MB of RAM. (Note that raw BIOS calls only support up to 64 MB, so you cannot have more with no memory manager at all.) Reportedly, HIMEM.SYS from DOS 7 (the one that comes with Windows 95) supports more than 64 MB, so you should be able to use that version in plain DOS mode and CWSDPMI, and get your program to run without paging.

The DJGPP development suite includes, besides the gcc and g++ compilers, ports of most of the GNU development tools, such as Make, File- and Textutils, Gawk, and even Bash (the GNU shell) and Emacs. When DJGPP programs run from the DOS box on Windows 95, they support long file names. And as I said before, DJGPP is completely free.

Sounds too good to be true? Visit http://www.delorie.com/djgpp/ and see for yourself.

If you have any further questions concerning DJGPP, post them to the comp.os.msdos.djgpp news group, or write to <[email protected]>, which is an email gateway into that group. I'm sure you will find that user support offered there is far superior to what you have with a typical commercial vendor, and the price is hard to beat.

P.S. Please note that I have no financial interest in DJGPP whatsoever.

Eli Zaretskii

Based on current trends, it won't be long before we're all in the same boat as Mr. Gammel — that is, if the Year 2000 problem doesn't kill us all first. Thanks to everyone who has offered help. — mb


Dear Editors,

I would like to comment on the article by Dwayne Phillips titled "Information Hiding in C via Modular Programming" (CUJ, January 1998). Mr. Phillips starts with a structured programming example of a stack, and declares it bad because it must expose implementation details via the stack_struct definition. He then demonstrates how to use modular programming to hide the implementation details.

Although the intent is good, the modular implementation sacrifices what may be considered an important feature of the original code — the ability to create multiple instances. Mr. Phillips admits this, and offers as a solution, "A programmer can work around this by making copies of the source code and naming the subroutines pusha, popa, pushb, popb, etc." To me, this is the worst form of code reuse. It can only lead to bloated code and a maintenance nightmare. Imagine having to add stack underflow checks to popa, popb, ... popz.

This restriction was unnecessary. A better solution would be to hide the stack structure behind a "handle." In spublic.h we could declare:

typedef void * STACK;

Application code would use the stack as:

STACK s;
s = initialize_stack();
push(s, 1);

Of course, implementation code would require a type cast:

int push(STACK s, element x)
{ struct stack_struct *stack =
  (struct stack_struct *)s; ... }

We can take this one step further by making STACK a partially opaque data structure. The "public" portion of this structure would contain only pointers to the stack access functions:

typedef struct tagStack {
     
  int (*push)
    (struct tagStack *, element);
  element (*pop)(struct tagStack*);
        ...
} *STACK;

Implementation code would declare in
sprivate.h:

struct list_based_stack {
  STACK the_stack;
  element the_data;
  ...
};

The application code now becomes:

s = new_stack();
s->push(s,1);

Now we can write a set of stack helper routines that work for all stack implementations. For example:

void empty_stack(STACK s)
{ while(!s->is_empty(s)) s->pop(s);}

We now have a framework that fully hides the implementation details (encapsulation). Application code uses the same function names regardless of the type of stack being used (polymorphism). New stack implementations don't need to implement functions such as empty_stack (inheritance). Moreover, unlike Mr. Phillips' implementation, we can create as many stacks as we need (instantiation).

In short, it is possible to use modular programming techniques in C without sacrificing an object-oriented approach.

Roger Lathrop
Fujitsu Software Corp.
lathropr%[email protected]


Dear Editor,

I read with interest Dwayne Phillips' article "Information Hiding in C via Modular Programming" in the January 1998 edition of CUJ. I've also had some interest in this topic, and would like to suggest an alternate approach which provides some degree of polymorphism, and is (in my opinion anyway) a bit cleaner and easier to work with.

This approach involves defining structs with function pointers and a void pointer for some (class-specific) data structure. This is certainly not a novel idea, but this starting point can provide a useful framework for defining "classes" in C.

For an example scenario, I suggest a program which is an interface to a set of three radio receivers. One of the receivers is connected to some network via a built-in ethernet interface, and accessed using TCP/IP. Another one is accessed through one of the machine's serial ports, while the third is accessed via a GPIB interface in the machine.

Further, suppose that all three radios were manufactured by different companies, and so have different control codes, status codes, and protocols, in addition to the differences in communications mechanisms.

The definitions given in rcvr.h (Listing 1) and the header for each receiver to be controlled are all the controlling program needs to include in order to handle any radio connected to it, as long the makefile links with one or more libraries that implement whatever class(es) it uses.

The implementation of each receiver class lives in a library (or file) which has a function corresponding to each of the function pointers in struct Rcvr. Each library also defines a constructor and destructor function, with names that reflect what kind of receiver they instantiate and destroy.

The constructor function in each library is responsible for allocating an instance of the struct (if the argument is zero), doing whatever initialization is needed for the radio, and allocating and initializing the data struct, which may be as complex as it needs to be.

The destructor function in each library is responsible for doing whatever cleanup/shutdown is needed on the radio. It also is responsible for deallocating any memory owned by the receiver-specific data structure (I/O buffers, etc), the data structure, and the Rcvr struct itself.

An example stub implementation is given in Listing 2 (Rcvr_a.h) and Listing 3 (Rcvr_a.c), and an example main routine is given in Listing 4 (main.c).

The C compiler will not supply a this pointer to the "object" as the C++ compiler does, so one must be passed as a parameter to each invocation of a function pointer, to provide access to the receiver-specific data struct. This can become annoying, and macros may be useful for automating the passing of the first parameter.

If another receiver is added to this example, the changes required would be limited to implementing and linking another library, including the additional header file, extending the array of receivers, and instantiating the additional one in main.c. If other common aspects are similarly encapsulated (communication interfaces, for example), the addition of a new receiver would not have to duplicate code.

The examples are more pseudocode than anything else, and error checking has been left out for clarity.

Joe Halpin
[email protected]

Dwayne Phillips's implementation is, admittedly, among the simpler of information hiding techniques in C. It does not pretend to anything so grand as polymorphism — and both you and Mr. Lathrop have ably demonstrated that polymorphism is possible in C. But perhaps you have also demonstrated why C++ was invented in the first place. The more object-oriented techniques you throw into a C program, the more it cries out to be rewritten in C++. Dwayne's article is meant to address situations in which C++ is not a very good option, or no option at all. However, it should probably be considered just the beginning of wisdom in information hiding. Thanks for writing. — mb


Editor,

Having just begun to learn C++ I found that if the sum function below has a return type of int it will not assign to a and b (passed as references) the value 5, but if the function returns void it does perform the assignments. Why is this so?

#include<iostream.h>
void sum(int &x, int &y)
{  x=5;
   y=5;
 //  return 0;

</p>
}
     
main()
{
  int a,b;
  a=1;
  b=2;
  sum(a,b);
  cout << " a " << a << "b " << b << endl;
  return 0;
}

Padraic Berry

No good reason that I can imagine. You need to check your work. The only reason why the assignments should fail is if you make the parameters non-references. And sometimes in a larger program, or one with template functions, you're not calling the function you think you are. But that shouldn't be the case in this simple example. — pjp o



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.