Search

Sponsored Links

Meta

Categories

Archives

Recent Posts

RSS Feeds

08
Dec

C++ Advanced Tutorial - Lesson 7

Related Blog Items

Please refer Lesson 6..

7. C - LIKE CODE
7.1 Redirecting Input & Output on UNIX/DOS Systems
7.2 Variable-Length Argument List
7.3 Command-Line Arguments
7.4 Program Termination with Exit and Atexit
7.5 Type Qualifier volatile
7.6 Suffixes for Primitives
7.7 Signal Handling
7.8 C-Style Dynamic Memory Allocation
7.9 Unconditional Branch: Goto
7.10 Union
7.11 Linkage Specification extern “C”
7.12 __stdcall
7.13 typedef

7. C - LIKE CODE

7.1 Redirecting Input & Output on UNIX/DOS Systems

Normally a program’s input comes from keyboard and output goes to screen. In most of the computer systems - UNIX and DOS systems in particular - it is possible to redirect inputs to come from a file, or redirect outputs to a file. They can be achieved on the system command line.

=>Redirect Input and pipelining

Key in the following on the command line in either UNIX or DOS:

$ program-name < filename

it runs the program with its input directed to the file. “<" is called the redirect input symbol.
The other method to redirect input is pipelining. A pipeline "|" causes the output of one program to be directed as the input to another program:

$ program1 | program2

This causes the output of program 1 to become the input of program 2.

=>Redirect Output
$ program-name > filename

it runs the program, with its output redirected to the file. “>” is called the redirect output symbol.
Using the append output symbol “>>”, the program output can be appended to the end of one file:

$ program-name >> filename

7.2 Variable-Length Argument List

This feature is a C feature. In C++ we use method overloading.
To indicate that a method receives an unspecified number and type of arguments, put “” in the end of the argument list. The header file of the macros and definitions is in .

int sum(int i, ...)
{ 
  int sum = 0;
  va_list a;
  va_start(a, i);
 
  for (int k = 1; k <= i; k++)
    sum += va_arg(a, int);
 
  va_end(a);
  return sum;
}
 
int main()
{
  int a = 1, b = 2, c = 3, d = 4;
  cout << sum(1, a);
  cout << sum(2, a, b);
  cout << sum(3, a, b, c);
  cout << sum(4, a, b, c, d);
}

va_list is a type. a is an object of va_list type, which will be used by other macros to get each argument from the list.
va_start initializes the va_list object, taking 2 arguments: the ap1 object and the last argument before the “…”.
va_arg(a, int) takes two arguments: the va_list object and the type of the object expected in the argument list, and returns the next argument in the argument list.
va_end(ap1) facilitate a normal return to the caller.

7.3 Command-Line Arguments

In many systems - UNIX and DOS in particular - it is possible to pass arguments to main from a command line. This is achieved by including two parameters in main’s parameter list: integer argc indicates the number of passed arguments, and argv is an array of strings to hold the arguments. This method can be used to pass information to a program, such as options and filename.
Command line:

$ program-name file1 file2

Program:

int main(int argc, char * argv[])
{
  if(argc != 3)
    cout << "Wrong arguments! \n";
  else
  {
    ifstream file1(argv[1], ios::in);
    ofstream file2(argv[2], ios::out);
    ...
  }
}

7.4 Program Termination with Exit and Atexit

The general utilities library provides methods to terminate program execution other than conventional return from main.

Method exit forces a program to terminate as if it executes normally. It is often used when an error is detected in input or file can not be opened. It has one argument, which is normally one of the two symbolic constants: EXIT_SUCCESS and EXIT_FAILURE. This argument is returned to the calling environment.

Method atexit takes a method name as argument. It registers this termination method to the program, so that when the program has a successful termination - either when return from main or exit called, that termination method will be called. This method can not have arguments or return type.

7.5 Type Qualifier volatile

Type qualifier volatile is used on the definition of a variable, to notify the compiler that this variable may be altered from outside the program so it is not under complete control of the local program. Thus, compiler can not perform optimization on it.

7.6 Suffixes for Primitives

u or U       unsigned.                      174U
l or L       long integer or long double    35L, 78.3L
ul or UL     unsigned long                  2387UL
f or F       float                          33.2F

7.7 Signal Handling

Unexpected events, also called signals, can terminate a program prematurely. For some of these signals, symbolic constants had been defined in signal handling library :

SIGABRT    Abnormal termination of the program
           such as a call to abort
SIGFPE     An erroneous arithmetic operation
           such as divide-by-zero or overflow
SIGILL     Detection of an illegal instruction
SIGINT     Receipt of an interactive attention signal
SIGSEGV    An invalid access to storage
SIGTERM    A termination request sent to the program

When the event happens, the corresponding signal happens.

The signal handling library provides method signal to catch the signal. It has two arguments: the name of the signal and the name of a signal handling method. It registers a signal handling method for a specific signal to the program, so that when that signal happens, that corresponding method will be called to handle that signal.

#include <iostream>
#include <signal>
 
void handling(int signal)
{  cout << "Signal SIGFPE is trapped! \n"; }
 
int main()
{
  signal(SIGFPE, handling);
  int a = 3, b;
  cout << "Please input b as 0: \n";
  cin >> b;
  cout << a/b << endl;
}

7.8 C-Style Dynamic Memory Allocation

In addition to malloc and free, the general utilities library provides two other methods for dynamic memory allocation - calloc and realloc, to create and modify dynamic arrays.

Method calloc dynamic allocates memory for an array:

void * calloc(size_t number, size_t size);

the first argument is the number of elements and the second is the size of each element. Altogether it determines the memory size needed. All the elements are initialized to 0. The method returns a pointer to the allocated memory, or NULL if memory is not allocated.

Method realloc changes the size of an array created by calloc:

void * realloc(void * ptr, size_t size);

the first argument is a pointer to the original object, second is the new size. The method returns either a pointer to the new memory or NULL if not successful. If the memory is reduced, the untouched part of memory remain unchanged.

If ptr is 0, it works exactly as calloc. If size is 0, all the memory is freed.

7.9 Unconditional Branch: Goto

There are mainly two situations that you need to use this unstructured programming technique:
Performance is more important than the structure of the program;

To exit nested control structures.

Try not to use goto except for this two reasons. Unstructured programming can lead to programs which are more difficult to debug, maintain and modify.
A goto statement is used together with a label. A label is an identifier followed by a colon.

int main()
{
  fstream file("test.txt", ios::out);
 
  for (int i = 0; i < 4; i++)
  {
    file << "Outer loop: i = " << i << endl;
 
    for (int j = 0; j < 4; j++)
    {
      file << "Inner loop: j = " << j << endl;
      if(i == 2 && j == 2) goto bottom;
    }
 
    file << endl;
  }
 
  bottom: file.close();
  return 0;
}

Output will be:

** Outer loop: i = 0
Inner loop: j = 0
Inner loop: j = 1
Inner loop: j = 2
Inner loop: j = 3

** Outer loop: i = 1
Inner loop: j = 0
Inner loop: j = 1
Inner loop: j = 2
Inner loop: j = 3

** Outer loop: i = 2
Inner loop: j = 0
Inner loop: j = 1
Inner loop: j = 2

7.10 Union

A union can have several members of different types including user-defined types. But these different members are actually sharing the same block of memory space. At one time a union can only hold one member.

At different times during a program’s execution, not all objects are relevant in the meantime. So a union combines a group of objects which are never used at one time to save space. The number of bytes used to store a union is at least the size of the largest member.

A union is declared in the same way as a struct or a class:

union Number 
{
  int x;
  float y;
};
Number n1;
n1.x = 33;

The following operations can be performed on an union:

Assignment (between same type of unions);
Take reference (&);

Access union members through “.” and “->”;

Unions can not be compared with each other for the same reason as structures.

An union can also have constructor, destructor or other methods, just like a class. But there is no inheritance or virtual issues for union.
An anonymous union is a union without a type name. Such a union can not be used to define objects later, but itself defines an object, whose members can be directly accessed in its scope just like normal variables, without using “.” or “->” operators:

union 
{
  int x;
  float y;
};

x = 33;

7.11 Linkage Specification extern “C”

This is to tell the compiler that the following function is not defined in this program, and it is the compiler’s job to look for the definition. This is also to inform the compiler that the following function was compiled as C code. C++ specially encodes method names for type-safe linkage, but C doesn’t. So when an attempt is made to link C code with C++ code, the method compiled in C will not be directly recognized.
For a single method:

extern “C” method prototype
For multiple methods:

extern "C"
{ method prototypes }

7.12 __stdcall

This is to indicate the calling convention which is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype. The following list shows the implementation of this calling convention:

Argument-passing order:              Right to left.
Argument-passing convention:         By value, unless a pointer or reference
                                     type is passed.
Stack-maintenance responsibility:    Called function pops its own arguments
                                     from the stack.
Name-decoration convention:          An underscore (_) is prefixed to the name.
                                     The name is followed by the at sign (@)
                                     followed by the number of bytes (in decimal)
                                     in the argument list. Therefore, the
                                     function declared as int func( int a,
                                     double b ) is decorated as follows: _func@12

7.13 typedef

typedef is used to assign an alias to an existing data type. Then this synonym can be used in place of the original data type:

typedef Card * PCARD;
...
PCARD pCard;

typedef can make a program easier to understand and modify, more portable. It can also be used to represent a very long type. In C programming, especially, if you define a struct in the following way

struct Employee 
{
  LPSTR name;
  LPSTR dept;
  short age;
};

When you create an instance of the struct, you have to say

struct Employee e1;

While if you use typedef to define the structure:

typedef struct 
{
  LPSTR name;
  LPSTR dept;
  short age;
} Employee;

when you create an instance you can say

Employee e1;

Popularity: 10%

You need to log on to convert this article into PDF


Related Blog Items

No Comments

No comments yet.

Leave a comment

*
To prove you're a person (not a spam script), type the security word shown in the picture.
Anti-spam image