Channels ▼
RSS

C/C++

Comparing Modula-2 and C++

Source Code Accompanies This Article. Download It Now.


JAN89: COMPARING MODULA-2 AND C++

Scott Ladd is a full-time freelance computer journalist. You can reach him at P.O. Box 61425, Denver, CO 80206.


Two of the hottest languages these days are Modula-2 and C++. They appeared in the early 1980s, and both are gaining in popularity. Each was designed and written by a single person: Niklaus Wirth created Modula-2, and C++ was developed by Bjarne Stroustrup. An additional similarity is that both languages are extended versions of earlier languages. This article contrasts Modula-2 and C++; it assumes you have a cursory familiarity with both Pascal and C (the root languages of Modula-2 and C++, respectively).

Modula-2 Background

Pascal was designed as a teaching language, to show students how to structure programs properly. It lacks intrinsic support for character strings, file I/O, and separately compiled modules. Pascal has many features that are useful in software development, and the language gradually gained popularity outside the academic community. Unfortunately, the vendors that implemented Pascal did not develop a standard for extending the language to cover its weak points. Thus, every Pascal compiler is unique, and porting programs between implementations is difficult.

Wirth intended Modula-2 to be the successor to Pascal. Modula-2's name implies one of its basic concepts: modular program design. Through the use of modular facilities, Modula-2 supports data abstraction and encapsulation. All I/O is done through procedures in modules as an aid to portability. As long as the interface to the I/O procedures does not change, the implementation of those procedures can be modified for different environments without having to make alterations in the programs using them.

Among high-level languages, only Modula-2 and Ada support multiprocessing. In addition, Modula-2 supports bit manipulation, generic types, and system-level access. Modula-2 (unlike Pascal) is well suited to the writing of system software such as operating systems and device drivers.

C++ Background

C is a powerful system-level language; in its original definition, however, it lacked many features necessary for large, complex projects. Stroustrup designed C++ to amend problems with the C language, in much the same way as Wirth designed Modula-2 to correct the deficiencies of Pascal. C++ provides capabilities for strong type checking, modular programming, and data abstraction while maintaining full compatibility with existing C programs.

Stroustrup borrowed the object-oriented paradigm from Smalltalk; classes and methods are the most significant additions he added to C in creating C++. In an object-oriented language, objects (data items) belong to classes (types), which have associated methods (functions). "Messages" are sent to objects via their class methods; the messages tell the objects how to act. For example, an object of class int would be given the message "add 1" by the ++ (increment) method. Although this concept can take some getting used to, it can be more appropriate than traditional program design methods.

C++ is often implemented as a translator. The C++ translator works much like the standard C preprocessor, converting C++ programs into C programs. A C compiler is then run on the output of the translator, producing executable code. By its nature, this process is cumbersome and slow. Recently, manufacturers have released true C++ compilers.

In addition to adding object-oriented capabilities to C, C++ offers other enhancements, including in-line functions, function prototyping (since added to the ANSI standard), and overloading. Because it retains all C's low-level facilities, C++ can be used for a wide variety of applications.

General Language Features

Modula-2 and C++ have the following general features:

  • Source code format -- Source code is case sensitive in C++ and Modula-2. All C++'s keywords must be in lowercase; Modula-2 requires uppercase.
  • Data types -- Both languages are rich in data types and allow the creation of new types. They offer long and short, signed and unsigned, integers and reals. Strings in both languages are handled as arrays of characters terminated by a zero (NUL) byte. Both languages have pointer types. C++ provides the capability to smoothly integrate new types through its class structure, while Modula-2 provides generic types and better control over data item visibility. Modula-2 provides SET types (including BITSET, which allows access to the individual bits of an item), whereas C++ has C's bit structures.
  • Functions and procedures -- Modula-2 has procedures, whereas C++ has functions. The purpose is the same in both languages: to provide callable routines with parameters and local variables. Modula-2 allows the nesting of procedures within procedures, using the same scoping rules as it does for variables. Modula-2 and C++ parameters can be passed either by reference or by value.
  • Control structures -- Here, too, there are no important differences. Although the syntax may vary, the capability is the same. Both languages have loops with tests at both the top and the bottom of the loop. The for, which iterates through a succession of values, is available in both languages. There is (of course) the ubiquitous if ..else ..endif conditional construct. Useful multiple-condition branches (switch in C++ and CASE in Modula-2) are available.
  • Library routines -- C++ uses the standard C library, which is extensive and robust. Wirth defined several standard modules in his definition of Modula-2, but these provided only minimal capabilities. Most Modula-2 vendors have created expanded libraries for their implementations.

Unique Features of Modula-2

Modula-2 is not a superset of Pascal; rather, it is an evolution of the earlier language. For example, one of Modula-2's most welcome enhancements over Pascal is its simplified block structure. A Modula-2 program is not filled with BEGIN...END pairs; each control structure has an implicit block terminated by an END statement. Where Pascal has functions and procedures (the former returns a value whereas the later does not), Modula-2 simply has procedures. A Modula-2 procedure returns a value if it is specified as doing so.

One fascinating feature of Modula-2 is its support for coroutines, which are individual processes within a program that run concurrently. This allows multiple tasks (within a program) to be performed simultaneously. A word processor, for example, could use coroutines to allow a document to be printed while another is being edited.

The strong type checking in Pascal prevents spurious errors but also causes difficulties. For instance, it is impossible to create a general function in standard Pascal that can accept arrays (such as character strings) of different sizes. Modula-2 introduces the concept of the open array parameter -- for example, a parameter to a procedure can be declared as an array without bounds (array of char). Any length array of the specified type (in this case, a character array) can be passed to that function. The procedure can then find out the actual length of the array with the built-in HIGH procedure.

Modula-2 also provides the generic type. A WORD type is equal in size to the default word size of the hardware it is running on. In the case of MS-DOS, a WORD type is 16 bits long. Any type of the same size (usually the INTEGER and CARDINAL types) is assignment compatible with WORD. An extension of this is that any value can be passed to an open array of type WORD (that is, a procedure parameter of type ARRAY OF WORD). The size of the array is the number of WORD types required to hold the value being passed.

The concept of modules allows Modula-2 programmers to control access to individually compiled portions of a program. The following object-oriented example illustrates how modules can be used.

Unique Features of C++

C++ refines and expands C while including all C's strengths. Several features of the emerging ANSI C standard are actually borrowed from C++. Examples of this are function prototypes, const, and void. Function prototypes were added so that C++ could do type checking or arguments; under the original K&R C, values of incorrect types could be passed to functions, often causing obscure errors. Const provides named constants. Adding void allowed the creation of generic pointers and made it possible to declare that a function does not return a value.

Overloading functions lets the programmers create several functions with the same name but differentiated by their parameters. Instead of C's current crop of absolute value functions (abs, dabs, fabs, and labs), a C++ implementation could have the following:

  overload      abs;
  int           abs(int i);
  long          abs(long l);
  float         abs(float f);
  double        abs(double d);

At compile time, the C++ compiler determines which version of abs to use based on the parameters it is being passed. This facility can make programs easier to understand.

It is possible to overload operators in C++. You can, for instance, create a new class that can use the same operators as existing classes. The section on object-oriented programming later in this article contains an example of operator overloading.

The object-oriented features of C++ are prominent. Object-oriented programming requires a change in thinking for many programmers; instead of thinking in terms of the nuts and bolts of programming, programmers are required to visualize a program as a series of processes applied to data items. This may seem to be a subtle distinction, but it must be mastered to truly appreciate and use an object-oriented language. The object-oriented features of C++ are illustrated in the section on the subject in this article.

C++ provides dozens of other extensions to C, including in-line functions, anonymous (unnamed) unions, and default function parameter values. There are dangers to the many features provided by C++. Whereas C has always been famous for providing the rope by which programmers hang their programs, C++ adds the noose. Care must be taken to avoid "going wild," especially with the overload capabilities.

An Object-Oriented Example

An object-oriented language is extensible, which means the programmer can create new data objects that are integrated into a program. In order to show how each language is used to create a new class of objects, I have implemented complex numbers in each language. Complex numbers are a superset of the real numbers, having both a real and an imaginary part. Complex numbers are used in a number of scientific calculations; this is one reason why Fortran directly supports complex numbers.

Both implementations are identical in function. First, you need to define the data elements of a complex number. In this case, the complex number has two floating-point components for its real and imaginary parts. Then, you determine what operations can be performed on complex numbers. In the example, the allowed operations are assignments, addition, subtraction, multiplication, division, and output. I used Zortech C++, Version 1.06, and JPI TopSpeed Modula-2, Version 1.11, to develop the examples.

In C++, a class is generally developed using two files. A header file contains the class description, and a source file holds the actual implementation. The example in Listings One - Three, page 102, follows this form.

A class in C++ looks like a structure; in fact, a structure is a special form of class. Those items listed in the private section cannot be accessed outside the class definition. Public data and functions are available for use outside the class scope. The example has only two private items, which are the two floating- point components of a complex value. (See Listings Four - Six, page 104.)

A "constructor" in C++ is called whenever an object of the class is created to initialize the object. The counterpart of a constructor is a "destructor," which can be used to deallocate any resources used by an object (once that object is no longer needed). The example does not require or implement a destructor.

Function overloading is used to provide several different constructors. Each constructor allows an object of class complex to be declared with different initialization values. The type and number of the initializers determines which constructor is used. The following code fragment shows how C++ determines which constructor to use:

  
   complex a; /* no values; uses 1st 
                      constructor */
   complex b(2.0,5.0); /* two real 
   values; uses 3rd constructor */
   complex c(b); /* complex value; uses 
                     2nd constructor */

Note that the first constructor is defined in the class definition; there is no external function for it. This constructor is compiled into in-line code, avoiding the overhead of a function call when declaring complex values without initializers.

Modula-2 does not support a specific class structure, but the same effect can be created through the use of modules. Modula-2 uses two files to create modules called the definition and implementation modules. The definition module defines the interface to the data elements and procedures stored in the implementation. Unless it is defined in the definition module, an item is private to the implementation.

In order to prevent programmers from manipulating the component values of a complex item directly, an "opaque type" is used. The definition module lists the type COMPLEX (allowing programs to create items of that type) but does not expose the type's internal structure. Because Modula-2's opaque types must be pointers, the implementation module defines the COMPLEX type as a pointer to a structure containing two real values. The situation requires the functions Create and Destroy in order to allocate and deallocate space for the complex numbers. These are similar to C++ constructors and destructors, but they must be called explicitly by the program.

Modula-2 does not support overloading, so there is no way to assign functions to infix operators. C++ allows functions to be assigned to operators, so in C++ it is possible to say:

  a = b + (c * d);

Modula-2 requires a less readable construct:

  Multiply(temp1,c,d);   Add(a,b,temp1);

The process is identical; both languages use functions to simulate operators. The primary difference is that C++'s notation is more natural, making it easier for programmers to discern what is happening. Although the results are the same, most programmers would prefer the clarity of the C++ version.

Both implementations provide a function for displaying the value of complex number. The Modula-2 version uses a procedure that calls upon standard library procedures. In the C++ version, a function is declared that accesses the stream output functions of C++. The stream class is provided with C++. The << (left shift) operator has been overloaded in C++ to say "send the object on the right to the object on the left." Streams can be easier to use for simple output than library function calls. Complex numbers are displayed using built-in stream output functions for characters, strings, and floating-point numbers.

C++ offers other object-oriented features not shown in the example. New classes can be "derived" from other, pre existing classes, and characteristics can then be "inherited" from the original class.

Implementations

C++ and Modula-2 are young languages. Modula-2 has been more widely implemented; on the other hand, it has had slightly longer to get into the mainstream. C++ is just beginning to come into its own outside the Unix/AT&T environment. Currently, half a dozen Modula-2 compilers are available for the PC, whereas three C++ preprocessors and one C++ compiler are available. In the Macintosh world, Apple has announced that it will extend its C compiler to be a C++, and there are at least two Macintosh Modula-2 compilers.

The situation is similar when it comes to third-party add-on libraries. I know of only one company that provides object libraries for C++. There are a few companies that market products for Modula-2. Recently, several vendors of C libraries have begun to market Modula2 versions of their products. As the popularity of these products grows, so will the third-party support.

Conclusion

Modula-2 and C++ are powerful languages; both have bright futures. C++'s classes, methods, and overloading make it a powerful tool, but it has few restraints to keep programmers from being too "creative." Modula-2 is a strongly organized language with restraints to keep programmers within guidelines. It is not as extensible as C++, but it does implement its own unique features, such as SETs, coroutines, and open arrays. Which of these languages is more appropriate for a specific project will depend on the type of application and the experience of the programmers involved. Both languages are powerful and interesting to work with.

Bibliography

    1. Stroustrup, Bjarne. The C++ Programming Language. Englewood Cliffs, NJ.: Addison-Wesley, 1986.

2 Wirth, Niklaus. Programming in Modula-2. 3rd ed. New York,: Springer-Verlag, 1985.

_C++ VERSUS MODULA-2_

by Scott Ladd

[LISTING ONE]

<a name="003d_000e">

=======================
<a name="003d_000f">
[LISTING 1: COMPLEX.HPP]
<a name="003d_000f">
=======================

//    Header:      Complex
//    Version:     1.00
//    Date:        10-Sep-1988
//    Language:    C++
//    Purpose:     Provides the class "complex" for C++ programs.
//    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.

#include "stream.hpp"

class complex
    {
    private:
        double real;   // real part
        double imag;   // imaginary part

    public:
        // constructors
        complex (void)
            {
            real = 0.0;
            imag = 0.0;
            }

        complex (complex &c);
        complex (double &r, double &i);

        // value extraction methods
        double get_real (void);
        double get_imag (void);

        // assignment method
        void assign (double &r, double &i);

        // calculation methods
        complex operator = (complex &c);
        complex operator + (complex &c);
        complex operator - (complex &c);
        complex operator * (complex &c);
        complex operator / (complex &c);

        // output method
        friend ostream& operator << (ostream &s, complex &c);
    };





<a name="003d_0010"><a name="003d_0010">
<a name="003d_0011">
[LISTING TWO]
<a name="003d_0011">

=======================
<a name="003d_0012">
[LISTING 2: COMPLEX.HPP]
<a name="003d_0012">
=======================

//    Module:      Complex
//    Version:     1.00
//    Date:        10-Sep-1988
//    Language:    C++
//    Purpose:     Provides the class "complex" for C++ programs.
//    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.

#include "complex.hpp"
#include "stream.hpp"

// constructor: copy initializer
complex::complex (complex &c)
    {
    real = c.real;
    imag = c.imag;
    }

// constructor: real and imaginary parts specified
complex::complex (double &r, double &i)
    {
    real = r;
    imag = i;
    }

// retrieve real portion
double complex::get_real (void)
    {
    return real;
    }

// retrieve imaginary portion
double complex::get_imag (void)
    {
    return imag;
    }

// set the value of a complex object to a pair of real values
void complex::assign (double &r, double &i)
    {
    real = r;
    imag = i;
    }

// set the value of a complex number
complex complex::operator = (complex &c)
    {
    real = c.real;
    imag = c.imag;

    return *this;
    }

// add two complex numbers
complex complex::operator + (complex &c)
    {
    complex res;

    res.real = real + c.real;
    res.imag = imag + c.imag;

    return res;
    }

// subtract two complex numbers
complex complex::operator - (complex &c)
    {
    complex res;

    res.real = real - c.real;
    res.imag = imag - c.imag;

    return res;
    }

// multiply two complex numbers
complex complex::operator * (complex &c)
    {
    complex res;

    res.real = (real * c.real) - (imag * c.imag);
    res.imag = (imag * c.real) + (real * c.imag);

    return res;
    }

// divide two complex numbers
complex complex::operator / (complex &c)
    {
    complex res;
    double r, den;

    if (fabs(c.real) >= fabs(c.imag))
        {
        r = c.imag / c.real;
        den = c.real + r * c.imag;
        res.real = (real + r * imag) / den;
        res.imag = (imag - r * real) / den;
        }
    else
        {
        r = c.real / c.imag;
        den = c.imag + r * c.real;
        res.real = (real * r + imag) / den;
        res.imag = (imag * r - real) / den;
        }

    return res;
    }

// stream output of complex number
ostream& operator << (ostream &s, complex &c)
    {
    char buf[80];

    sprintf(buf,"%1g%+1gi",c.real,c.imag);
    return (s << buf);
    }






<a name="003d_0013"><a name="003d_0013">
<a name="003d_0014">
[LISTING THREE]
<a name="003d_0014">

=======================
<a name="003d_0015">
[LISTING 3: COMPTEST.CPP]
<a name="003d_0015">
=======================

//    Program:     CompTest
//    Version:     1.00
//    Date:        10-Sep-1988
//    Language:    C++
//    Purpose:     Provides the class "complex" for C++ programs.
//    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.

#include "complex.hpp"

void main()
    {
    complex a(1.0,2.0),
            b(-1.5,-5.5),
            c;

    cout << "a = " << a << " b = " << b << " c = " << c << "\n";
    c = a + b;
    cout << c << "\n";
    c = c - b;
    cout << c << "\n";
    c = b;
    cout << c << "\n";
    c = b * a;
    cout << c << "\n";
    c = c / a;
    cout << c << "\n";
    c = b / b;
    cout << c << "\n";
    }




<a name="003d_0016"><a name="003d_0016">
<a name="003d_0017">
[LISTING FOUR]
<a name="003d_0017">

=======================
<a name="003d_0018">
[LISTING 4: COMPLEX.DEF]
<a name="003d_0018">
=======================

DEFINITION MODULE Complex;
(*
    Version:     1.00
    Date:        11-Sep-1988
    Language:    Modula-2
    Purpose:     Provides the type "complex" for Modula-2.
    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.
*)

TYPE
    COMPLEX;

PROCEDURE Create(VAR C : COMPLEX);

PROCEDURE Destroy(VAR C : COMPLEX);

PROCEDURE GetReal(C : COMPLEX) : LONGREAL;

PROCEDURE GetImag(C : COMPLEX) : LONGREAL;

PROCEDURE Assign(VAR C : COMPLEX; R, I : LONGREAL);

PROCEDURE Equate(VAR C1 : COMPLEX; C2 : COMPLEX);

PROCEDURE Add(VAR C : COMPLEX; C1, C2 : COMPLEX);

PROCEDURE Sub(VAR C : COMPLEX; C1, C2 : COMPLEX);

PROCEDURE Mult(VAR C : COMPLEX; C1, C2 : COMPLEX);

PROCEDURE Div(VAR C : COMPLEX; C1, C2 : COMPLEX);

PROCEDURE WriteComplex(C : COMPLEX);

END Complex.





<a name="003d_0019"><a name="003d_0019">
<a name="003d_001a">
[LISTING FIVE]
<a name="003d_001a">

=======================
<a name="003d_001b">
[LISTING 5: COMPLEX.MOD]
<a name="003d_001b">
=======================

IMPLEMENTATION MODULE Complex;
(*
    Version:     1.00
    Date:        11-Sep-1988
    Language:    Modula-2
    Purpose:     Provides the type "complex" for Modula-2.
    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.
*)

FROM Str     IMPORT FixRealToStr;
FROM IO      IMPORT WrStr, WrChar;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;

TYPE
    COMPLEX = POINTER TO RECORD
                  Real : LONGREAL;
                  Imag : LONGREAL;
              END;

PROCEDURE Create(VAR C : COMPLEX);
  BEGIN
    NEW(C);
    C^.Real := 0.0;
    C^.Imag := 0.0;
END Create;

PROCEDURE Destroy(VAR C : COMPLEX);
  BEGIN
    DISPOSE(C);
END Destroy;

PROCEDURE GetReal(C : COMPLEX) : LONGREAL;
  BEGIN
    RETURN C^.Real;
END GetReal;

PROCEDURE GetImag(C : COMPLEX) : LONGREAL;
  BEGIN
    RETURN C^.Imag;
END GetImag;

PROCEDURE Assign(VAR C : COMPLEX; R, I : LONGREAL);
  BEGIN
    C^.Real := R;
    C^.Imag := I;
END Assign;

PROCEDURE Equate(VAR C1 : COMPLEX; C2 : COMPLEX);
  BEGIN
    C1^.Real := C2^.Real;
    C1^.Imag := C2^.Imag;
END Equate;

PROCEDURE Add(VAR C : COMPLEX; C1, C2 : COMPLEX);
  BEGIN
    C^.Real := C1^.Real + C2^.Real;
    C^.Imag := C1^.Imag + C2^.Imag;
END Add;

PROCEDURE Sub(VAR C : COMPLEX; C1, C2 : COMPLEX);
  BEGIN
    C^.Real := C1^.Real - C2^.Real;
    C^.Imag := C1^.Imag - C2^.Imag;
END Sub;

PROCEDURE Mult(VAR C : COMPLEX; C1, C2 : COMPLEX);
  BEGIN
    C^.Real := (C1^.Real * C2^.Real) - (C1^.Imag * C2^.Imag);
    C^.Imag := (C1^.Real * C2^.Imag) - (C1^.Imag * C2^.Real);
END Mult;

PROCEDURE Div(VAR C : COMPLEX; C1, C2 : COMPLEX);
  VAR
    r1, r2 : LONGREAL;
  BEGIN
    IF ABS(C2^.Real) >= ABS(C2^.Imag) THEN
        r1 := C2^.Imag / C2^.Real;
        r2 := C2^.Real + r1 * C2^.Imag;
        C^.Real := (C1^.Real + r1 * C1^.Imag) / r2;
        C^.Imag := (C1^.Imag - r1 * C1^.Real) / r2;
    ELSE
        r1 := C2^.Real / C2^.Imag;
        r2 := C2^.Imag + r1 * C2^.Real;
        C^.Real := (C1^.Real * r1 + C1^.Imag) / r2;
        C^.Imag := (C1^.Imag * r1 - C1^.Real) / r2;
    END; (* IF *)
END Div;

PROCEDURE WriteComplex(C : COMPLEX);
  VAR
    S  : ARRAY [0..10] OF CHAR;
    OK : BOOLEAN;
  BEGIN
    FixRealToStr(C^.Real, 3, S, OK);
    WrStr(S);
    FixRealToStr(C^.Imag, 3, S, OK);
    IF C^.Imag >= 0.0 THEN
        WrChar('+');
    END; (* IF *)
    WrStr(S);
    WrChar('i');
END WriteComplex;

END Complex.





<a name="003d_001c"><a name="003d_001c">
<a name="003d_001d">
[LISTING SIX]
<a name="003d_001d">

=======================
<a name="003d_001e">
[LISTING 6: COMPTEST.MOD]
<a name="003d_001e">
=======================

MODULE CompTest;
(*
    Version:     1.00
    Date:        11-Sep-1988
    Language:    Modula-2
    Purpose:     Tests the Complex module
    Copyright 1988 by Scott Robert Ladd. All Rights Reserved.
*)

FROM Complex IMPORT COMPLEX,
                    Create, Destroy, Assign, Equate,
                    Add, Sub, Mult, Div, WriteComplex;

FROM IO      IMPORT WrStr, WrLn;

VAR
    a, b, c : COMPLEX;
    r1, i1  : LONGREAL;
    r2, i2  : LONGREAL;

BEGIN
    r1 :=  1.0;
    i1 :=  2.0;
    r2 := -1.5;
    i2 := -5.5;

    Create(a);
    Create(b);
    Create(c);

    Assign(a,r1,i1);
    Assign(b,r2,i2);
    Assign(c,r1,i2);

    WrStr("a = ");
    WriteComplex(a);
    WrStr(" b = ");
    WriteComplex(b);
    WrStr(" c = ");
    WriteComplex(c);
    WrLn;

    Add(c,a,b);
    WriteComplex(c);
    WrLn;

    Sub(c,c,b);
    WriteComplex(c);
    WrLn;

    Mult(c,b,a);
    WriteComplex(c);
    WrLn;

    Div(c,c,a);
    WriteComplex(c);
    WrLn;

    Div(c,b,b);
    WriteComplex(c);
    WrLn;

    Destroy(a);
    Destroy(b);
    Destroy(c);

END CompTest.











Copyright © 1989, Dr. Dobb's Journal


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.
 

Video