C++ to C in an hour

C++ to C in an Hour

Main Differences

struct instead of class

I/O is different, using printf and scanf instead of cin and cout

Function prototypes are subtlely different.

Memory management is more basic, using malloc and free

Can still make programs object-oriented and modular.

Comments

// doesn't work in C, only in C++ and Java

Must use /* blah */ instead in ANSI C.

This works with C, C++ and Java, so use it.

Structures instead of classes

In C++

   class Employer
   {
      int number;
      Person *employees;
      
      void hire(Person p);
      void fire(Person p);
   }
Structures instead of classes

In C

   typedef struct Employer  Employer;
   
   struct Employer
   {
      int number;
      Person *employees;
   }
   
   void employer_hire(Employer me, Person p);
   void employer_fire(Employer me, Person p);

Putting the structure name within the function name is a good idea, to avoid clashing with any other functions called hire or fire.

The instance of the structure you are working on (the "object" in O-O terminology) is the first parameter. In C++, that object is implicit and is always called this. In C, we must give it an explicit parameter name.

Recursive structures
   typedef struct Employer  Employer;
   typedef struct Person    Person;
   
   struct Employer
   {
      int number;
      Person *employees;
   }
   
   struct Person
   {
      int number;
      Employer *employers;
   }

Note that the typedefs are both before the structure definitions. This allows the names to be used within either structure.

Strings

Strings are just arrays of ASCII chars, and terminated by a char of value 0.

What does the string "Hello world" look like in memory?

   H e l l o   w o r l d /0

Here's how to find the length of a string:

   int strlen(char *s)
   {
      int length;

      for (length = 0; *s != '/0'; s++)
         length++;
      return length;
   }

Functions such as strlen are already defined, just

   #include <string.h>
The main function

The main function should be defined as

   int main(int argc, char *argv[])
   {
      /* some code */
      return 0;
   }

The argc parameter tells you how many parameters were passed on the command line, and the argv parameter is an array of strings containing those parameters. There is an extra string at the end of the array, which is guaranteed to be NULL.

Output

In C++ you can print something to the standard output stream by using << with the stream cout:

   cout << i << s;         // C++

In C we use the printf function:

   printf("%d%s", i, s);      /* C */

Or we can use the fprintf function and the stdout stream:

   fprintf(stdout, "%d%s", i, s);   /* C */

There is also a predefined stream called stderr which works in the same way as stdout, and corresponds to the cerr stream in C++.

Using I/O in C

To use any C input/output functions, we must do the following:

   #include <stdio.h>

This allows the current source file to know about the standard I/O functions, such as printf. It's the C equivalent of doing the following in C++:

   #include <iostream>

The stdio.h header file should also include a definition of NULL as something like

   #define NULL ((void*)0)

so you should never need to declare this yourself. Note it is NULL in C, not null (as in Java).

Using printf

The %d and %s in printf tell the function how to print the other parameters.

%d means print a decimal integer, e.g. 1234

%x means print a hexadecimal integer, e.g. f1d0

%lx means print a hexadecimal long integer, e.g. f1d0d1d0

%f means print a floating point number, e.g. 3.14159

%s means print a string, e.g. Hello world.

Look up how the precision works, using man printf.

Input

There is a standard input stream stdin which works like cin. Functions such as scanf automatically use stdin, so

   cin >> i >> s;         // C++

becomes

   scanf("%d%s", &i, s);      /* C */

or

   fscanf(stdin, "%d%s", &i, s);   /* C */

Note the need for pointers to int (but strings are already pointers to char).

C++ equivalents to printf and scanf

In C++ there are functions called form and scan which do the same thing as printf and scanf:

   cout.form("%d%s", i, s);   // C++
   cin.scan("%d%s", &i, s);   // C++
Function Prototypes

Use void when defining a function prototype if there is no return type, or no parameters to the function.

   void func(void);   /* ANSI C */

This is different to Java and C++, where you can write

   void func();      /* Java */

Put prototypes and definitions of structures into header files, which have a suffix of .h

Source Code Files

C source code files are suffixed with .c and should contain functions and any definitions which you want to use just inside that file. If you want a function to not be visible outside the file, declare it using the static keyword.

   static void func(int x, int y)
   {
      /* some code here */
   }

If you want a function to be visible outside the file, put a function prototype in a header file, and declare the function normally. Put declarations and constants into header files too if another file will need them.

   #define BUFFER_SIZE (1<<27)
   
   int countlength(char *name);
Header Files and #include

Names of header files traditionally end in .h

Never #include a C source code file, only #include header files.

Inside a header, just put function prototypes, enums and #defines, and struct and union definitions. Don't put anything which compiles to actual code. Specifically, don't put functions inside a header.

Also, avoid including another header from inside a header.

The << and >> Operators

Bit shift operators move bits around in an integer. Does not perform I/O in ANSI C.

   int i, j;
   
   i = 0x0039;
   j = i << 4;     /* j now 0x0390 */
   j = j << 8;     /* j now 0x9000 */
   j = j >> 4;     /* j now 0x0900 or 0xF900 */
   j = j & 0x0F00; /* j now 0x0900 */

Left shifting puts zeros into the new bits, but right shifting may put zeros or ones if the number is negative (it's implementation dependent).

Memory management in C

Memory is an array of bytes in the C language (and in most computer's hardware). C has functions to ask for blocks of that memory from the operating system (malloc) and return such blocks to the operating system for use by other programs (free):

   Employee *e;

   e = malloc(sizeof(Employee));
   init_employee(e);    /* your own initialiser */

   /* do some work using e ... */

   free(e);

If you do not free a block of memory, it will be freed at the end of the program for you. Sometimes you will want to free the memory during the running of the program, however.

Type conversion

In the C language, there are few circumstances where type conversion occurs automatically.

This is a good thing.

In C++, you can sometimes convert one type of data into another type of data implicitly (automatically):

   string s = "123";
   int i = s;

This is bad news. This feature has deliberately not been implemented in Java, because type conversion should, by and large, be explicit - the programmer should control it.

There are exceptions to this rule, but in general, automatic type conversion can lead to errors being silenced (always a bad thing).

Type conversion in C

In C:

   char *s = "123";
   int i = (int) s;      /* doesn't work */

The above does not work. The only type conversions in C are between numeric types such as int and float. Use functions such as atoi(s) to return the integer value printed inside a string.

atoi stands for alphanumeric string to integer. You can guess what atof does.

The abort function

What does abort do?

It crashes your program, and on UNIX systems it causes a core dump.

Why are core dumps good?

Because they produce debugging information.

Using gdb

The gdb program is a debugger which can tell you where an error occurred in your program.

Use it like this:

   bash$ ztest 3
   ztest: overwriting the end of a block.
   zfree: end buffer corrupted at offset 10. Block length is 10.
    Start buffer is 0x5AFEC0DE.
    End buffer is 0xC0CAC01A.
   Abort (core dumped)
   
   bash$ gdb ztest core
   Core was generated by `ztest 3'.
   Program terminated with signal 6, Aborted.
   #0  0xef774594 in _kill ()
   
   (gdb) where
   #0  0xef774594 in _kill ()
   #1  0xef73a62c in abort ()
   #2  0x11314 in zfree (v=0x22860) at zutil.c:146
   #3  0x10c78 in main (argc=2, argv=0xeffff8dc) at ztest.c:52
   (gdb) 
Using Makefiles

Makefiles specify rules which allow the compiler to just recompile the bits which have changed since the last compilation. They look like this:

   rcat:   rcat.o zutil.o
      gcc rcat.o zutil.o -o rcat

The above is one single rule, called rcat. Note that the second line must have a tab character at the start. To use this makefile to create the rcat program, type:

   make rcat

The rule specifies that the files rcat.o and zutil.o are needed before we can proceed. (The make program knows how to turn .c files into .o files). The second line of the rule says what to do after that, in this case we are using gcc to compile the object files into an executable called rcat.

Makefiles must be named makefile or Makefile.

Compiler Warnings are Good

Turn compiler warnings on because they help you find bugs.

   gcc -ansi -Wall -g -pedantic

This turns on a lot of warnings for common problems. Often the compiler is better at noticing low-level details than I am.

On your compiler at home, turn on ANSI C mode, and switch on as many warnings as seem sensible. Always test your code at university using gcc before submitting.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值