C or Pascal?
Volume: | | 8
|
Number: | | 5
|
Column Tag: | | Getting Started
|
Related Info: Window Manager
C or Pascal?
Which is the best language?
By Dave Mark, MacTutor Regular Contributing Author
If my writing seems a little jumpy this month, theres a good reason for it. Im thrilled, pleased, and proud to announce the birth of my first child, Daniel Justin, on July 27th, 1992 at 5:39 pm. While I could easily write an entire column describing Daniels birthday, suffice it to say that things went relatively smoothly, and we are all doing fine (and no, Dad, the boy doesnt have a job yet!).
C and Pascal
Recently, weve been getting a lot of mail concerning programming in C vs. programming in Pascal. Some folks want to know which language is better for Macintosh programming. Others want some help translating C examples into Pascal and Pascal examples into C. So far, this column has leaned pretty heavily in the C direction. In this months column, Ill try to give Pascal equal time.
C or Pascal: Whats the Best Language?
C and Pascal are both procedural, as opposed to object, programming languages. Pascal is a rigidly formal language, and is said to be strongly typed. C is an informal language, and is very loosely typed. While Pascal forces you to follow a very specific, rigidly defined programming style, C offers more notational flexibility.
For example, consider this snippet of C code:
/* 1 */
void main()
{
int age, weight;
for ( age=0,weight=0; age<=20; age++,weight++ )
{
}
}
This for loop initializes two variables, sets the end condition, and increments both variables each time through the loop (the three dots represent the inner workings of the loop). Notice how compact this code is.
To emphasize this point, check out the Pascal version of the same loop:
{2}
program MyProgram;
var
age, weight: INTEGER;
begin
weight := 0;
for age := 0 to 20 do
begin
weight := weight + 1;
end;
end.
Beginners may find the Pascal code easier to read than the C code. The Pascal example is very straight-forward. Each statement consists of a single expression and the flow is very simple.
The C example, on the other hand, is more complex. Lots of action is crammed into a single line of code. One advantage to this approach is that by allowing several variables to be initialized or incremented at the same time, the structure of the loop is more natural. In the Pascal loop, weight is initialized explicitly, while age is initialized in the for statement. In the C example, both variables are modified in the same breath, more closely matching the intent of the loop.
Pascal is more straight-forward, C is more complex. Now the question is, which of these two languages is better?
The answer to this question depends on your point of view. Some folks claim that Pascal is a superior language because its straight-forwardness makes it somewhat easier to learn than C. Is this your first programming language? If so, Pascal might be the choice for you.
The other side of the coin is Cs power. While Pascal is a safe, dependable Volvo, C is a turbo-charged Porsche, both powerful and dangerous. If you pick C as your language, youll be forced to develop a carefully considered coding style. Pascal is a much more forgiving language, but C will really let you fly!
The Support Factor
Whether you are a beginner or an old-timer, youd probably do just fine no matter which of the two languages you pick. If you need a little push in one direction or another, consider the support factor.
Learning a new language can be pretty tough. The right support can make a huge difference. For example, if your best friend is a C guru, you might choose C over Pascal (that is, if your buddy wont mind your harassing him or her with questions all the time). If you have access to a Pascal course at your school, Pascal might be your best bet. Once you learn one of these languages, its pretty easy to come up to speed on the other one.
One place you can always turn to for support is your local technical bookstore. Books are usually a pretty good investment, and there are lots of good C and Pascal titles available.
All Things Being Equal
If none of this reasoning has swayed you in one direction or another, consider this argument for C over Pascal. There is a strong movement in programming circles towards object programming. This movement is likely to get a lot stronger in the coming years. Apple is doing most of their development in C++, an extremely popular object programming language that happens to be a superset of C.
Pascal also has a related object programming language, Object Pascal. Most likely, in coming years youll be able to develop complete Macintosh applications in both Object Pascal and C++. So why am I leaning towards C and C++? Support, support, support...
Heres why: Go down to your local Software Etc. (or whatever technical bookstore youve got in your neck of the woods) and count all the Pascal/Object Pascal books. Next count all the C/C++ books. Chances are, the C and C++ books will outnumber the Pascal/Object Pascal books by at least five to one. This should tell you something.
C and C++ have skyrocketed in popularity in recent years and interest in Pascal and Object Pascal has cooled off. All things being equal, Id choose C over Pascal. Nothing against Pascal, you understand. Its just a question of support. My feeling is, over the coming years, Im going to be able to find C/C++ support a lot more readily than Pascal/Object Pascal support.
Navigating Between C and Pascal
Whether you select C or Pascal, youll want to be able to navigate between the two languages. One big reason for this is the proliferation of C and Pascal sample code. If you are trying to solve a specific Macintosh interface problem, theres no substitute for an example. Murphys Law being what it is, if you are programming in one language, the only example youll be able to turn up will be in the other language.
C programmers have another reason for learning to read Pascal code. Most of the original Macintosh operating system was written in Pascal. Because of this, most of the examples in Inside Macintosh and in the Macintosh Technical Notes are in Pascal. In addition, the Toolbox routines were designed to take advantage of the Pascal parameter passing mechanism.
The remainder of this column will explore some of the differences between C and Pascal and will help C programmers call Toolbox routines designed for Pascal programmers.
Calling the Toolbox From C
Pull out your copy of Inside Macintosh, Volume I, and turn to page 283. There youll find the calling sequence for the Toolbox routine GetNewWindow():
{3}
FUNCTIONGetNewWindow(windowID:INTEGER;
wStorage:Ptr;
behind:WindowPtr ): WindowPtr;
The first word in this calling sequence tells you whether the routine being described returns a value or not. In the case of a FUNCTION, the routine returns a value of the type listed at the end of the calling sequence. The calling sequence above tells you that GetNewWindow() returns a WindowPtr.
If the routine is declared as a PROCEDURE, it doesnt return a value and is analagous to a C routine declared as a void.
Translating Pascal Types to C Types
Once youve figured out whether the Toolbox routine under consideration returns a value or not, youll need to figure out the C data types that correspond to each of the routines parameters. This process is actually pretty easy. For starters, take a look at this table:
Pascal Data Type THINK C Equivalent
INTEGER short
LONGINT long
CHAR short
BOOLEAN Boolean
A Toolbox parameter declared as an INTEGER corresponds to the THINK C type short. Both of these types are two bytes in length. The Pascal type LONGINT corresponds to the THINK C type long. The Pascal type CHAR corresponds to the THINK C type short, and the Pascal type BOOLEAN corresponds to the THINK C type Boolean. The Pascal type Ptr corresponds to a C pointer. In the Macintosh world, both pointers and Ptrs are four bytes in length. In C, a pointer is declared using the * operator.
In addition to these basic Pascal types, youll frequently encounter types specific to the Toolbox. For example, the Window Manager defines the type WindowPtr. When you run into one of these Toolbox types, just use them as is. Typically, the Toolbox types are named using the same conventions as the Toolbox routines. The name is divided into a series of words. The first letter of each word is an upper-case letter while the remainder of each word is spelled with lower-case letters. This gives you Toolbox types such as WindowPtr, Rect, and GrafPort.
Lets go back to the GetNewWindow() call presented earlier:
{4}
FUNCTIONGetNewWindow(windowID:INTEGER;
wStorage:Ptr;
behind:WindowPtr ): WindowPtr;
To call this routine from C, youll want to pass a short, a pointer, and a WindowPtr
as parameters. Finally, youll receive the result in a variable of type WindowPtr:
/* 5 */
#define kBaseResID 128
#define kMoveToFront (WindowPtr)-1L
WindowPtr window;
window = GetNewWindow( kBaseResID, nil, kMoveToFront );
Notice that we passed constants as parameters. As long as the values are of the proper type, this works just fine.
Remember, C is a case-sensitive language and Pascal is not. In Pascal, you can get away with spelling horrors like WINDowptr and WiNdOwPtR. In C, however, youd best get it right: WindowPtr.
C and Pascal Strings
In C, text strings are represented by a series of bytes terminated by a null byte, a byte with a value of 0. In Pascal, however, text strings are stored in a variable of type Str255. The first byte of a Str255 is known as a length byte and indicates the length of the text string. The string itself is imbedded in the bytes that follow the length byte. Since the length byte can hold values from 0 to 255, a Pascal text string can be anywhere from 0 to 255 bytes long. C strings are limited only by available memory.
For example, this figure shows a Pascal string containing the text string Hello, World!:
Figure 1
The first byte has a value of 13, describing the length of the text string. This figure, on the other hand, shows the same string represented as a C string:
Figure 2
Notice that the string is terminated by a byte with a value of zero.
When a Toolbox routine makes use of a Str255, you need to pass it a string in the Pascal format. For example, heres the calling sequence for the Toolbox routine DrawString():
{6}
PROCEDURE DrawString( s: Str255 );
You must call DrawString() with a proper Pascal string. THINK C helps you in this regard by offering a special escape sequence you can use to declare a Pascal string literal in C. If THINK C encounters the characters \p at the very beginning of a string literal, the string is stored as a Pascal Str255. For example, this call to DrawString() works like a charm:
/* 7 */
DrawString( \pHello, World! );
You might also find it useful to use \p in a #define:
/* 8 */
#define kMyString\pHello, World!
DrawString( kMyString );
This approach works just as well.
THINK C also provides the routines CToPStr() and PToCStr() to translate a C string to Pascal and a Pascal string to C. Note that these routines are not part of the Macintosh Toolbox. They are provided as a service by THINK C.
When to Use the &
Another important issue for C programmers concerns the & operator and its use in parameter passing. Pascal parameters are normally passed by reference. This means that you can pass an INTEGER into a routine and, if the routine modifies the INTEGER, the changed value goes back to the calling routine.
C normally passes parameters by value. In C, if you pass a short to a routine, and the routine modifies the short, the modification only affects the local copy of the short and not the calling routines copy. To pass a parameter by reference in C, youll typically pass a pointer to the variable:
/* 9 */
MyRoutine( &myVar );
Theres more to parameter passing than just sticking an & in front of any parameter you want to pass by reference. Heres a set of four rules you should use to decide when the & is appropriate when making Toolbox calls. These rules can be found in Volume I of the Mac C Primer:
1) If a parameter is declared as a VAR parameter in the Pascal calling sequence, precede it by an &. Heres the Pascal calling sequence for GetFNum():
{10}
PROCEDUREGetFNum( fontName: Str255;
VAR theNum: INTEGER );
Heres a C code fragment that calls GetFNum():
/* 11 */
short myFontNumber;
GetFNum( \pGeneva, &myFontNumber );
2) If the parameter is bigger than 4 bytes (as is the case with most Pascal and C data structures), precede it by an & whether or not it is declared as a VAR parameter. Heres the Pascal calling sequence for UnionRect():
{12}
PROCEDUREUnionRect( src1, src2: Rect;
VAR dstRect: Rect );
Heres a C fragment that calls UnionRect():
/* 13 */
Rect src1, src2, dstRect;
/* assign values to src1 and src2 */
UnionRect( &src1, &src2, &dstRect );
3) If the parameter is 4 bytes or smaller and is not declared as a VAR parameter, pass it without the &. This rule applies even if the parameter is a struct. This is the Pascal declaration of the routine PtToAngle():
{14}
PROCEDURE PtToAngle( r: Rect;
pt: Point;
VAR angle:INTEGER );
Heres a C fragment that calls PtToAngle():
/* 15 */
Rect r;
Point pt;
short angle;
/* assign values to r and pt */
PtToAngle( &r, pt, &angle );
Notice that pt was passed without a leading &. This is because Points are only 4 bytes in size. Most of the predefined Mac types are larger than 4 bytes in size. Point is one of the few exceptions.
4) If the parameter is a Str255, do not use an &, even if the parameter is declared as a VAR. This is the Pascal declaration of the routine GetFontName():
/* 16 */
PROCEDURE GetFontName( fontNum: INTEGER;
VAR theName: Str255 );
Here is an example of a Pascal string used in a Toolbox call:
{17}
Short fontNum;
Str255 fontName;
fontNum = 4;
GetFontName( fontNum, fontName );
Note that fontName was passed without a leading &.
Last Months Program In Pascal
Last month we worked through a program called PICTWindow. Since this column focused on Pascal, I thought you might like to see a Pascal version of PICTWindow. Here it is...
Create a new folder called PICTWindow. Follow the directions in last months column to create the resource file called PICTWindow.Π.rsrc and copy the file into the PICTWindow folder.
Next, launch THINK Pascal and create a new project in the PICTWindow folder. Select Run Options... from the Run menu and click on the Use Resource File: checkbox. When prompted, select the PICTWindow.Π.rsrc file in the PICTWindow folder, then click the OK button.
Next, select New from the File menu to create a new source code window. Type in this source code:
program PICTWindow;
const
kBaseResID = 128;
{----------------> WindowInit <--}
procedure WindowInit;
var
window: WindowPtr;
begin
window := GetNewWindow(kBaseResID, nil, WindowPtr(-1));
if window = nil then
begin
SysBeep(10);
ExitToShell;
end;
ShowWindow(window);
SetPort(window);
end;
{----------------> DrawMyPicture <--}
procedure DrawMyPicture;
var
pictureRect: Rect;
picture: PicHandle;
begin
picture := GetPicture(kBaseResID);
if picture = nil then
begin
SysBeep(10);
ExitToShell;
end;
pictureRect := picture^^.picFrame;
OffsetRect(pictureRect, -pictureRect.left, -pictureRect.top);
DrawPicture(picture, pictureRect);
FrameRect(pictureRect);
end;
{----------------> PICTWindow <--}
begin
WindowInit;
DrawMyPicture;
while not Button do
;
end.
Finally, save the source code as PICTWindow.p and add the file to the project. Select Go from the Run menu to run the program. Enjoy!
Next Month
Next month well return to the topic of resources. Till then, its back to late nights and diaper changing. Coming, Daniel...