메뉴 건너뛰기


Developer > Application

Java How to Convert C to Java

2013.12.28 03:48

푸우 조회 수:15686



This document describes what needs to be done to translate C code to Java. Jazillian does all of this automatically.

Table Of Contents

  1. Preprocessor
    1. #define
      1. Constants
      2. Macro Functions
      3. Straight Text Replacement
      4. Unneeded Defines
    2. #ifdef and #ifndef
    3. #if
    4. #include
    5. #pragma
    6. #error
    7. Preprocessor Constants: __LINE__, etc
    8. typedef
  2. The main() function
    1. Hello, World
    2. argc And argv
    3. getopt
  3. Syntactic differences
    1. Valid Identifiers
    2. extern
    3. Parameterless Functions: "void *"
    4. static variables and functions
    5. Conflicting Variables
    6. Missing function and variable types
    7. Access keywords: "public", "private", etc.
    8. K&R-style functions
    9. Function Declarations
    10. Variable Declarations
    11. array declarations
    12. no comma operator
    13. Consecutive Strings
    14. Unused Keywords
      1. "signed" and "unsigned" keywords
      2. "register" keyword
      3. "const" keyword
    15. Redefined Keywords
    16. Static Functions
    17. Type conversions and casting
    18. VarArgs and "..."
  4. Data Types
    1. boolean Variables
    2. boolean Functions
    3. What type is Zero?
    4. char vs. int
    5. Array Indexes are int
    6. Loss of Precision
  5. Strings
    1. The String class
    2. charAt
    3. No setCharAt() function
    4. String Functions
    5. Character Functions
    6. null String Termination
  6. Data Structures
    1. struct
      1. struct Becomes a Class
      2. Initialization
      3. Unnamed Structures
    2. union
    3. enum
  7. Passing the Java Compiler
    1. Uninitialized Variables
    2. Unreachable Statements
    3. No Static Local Variables
  8. Flow of Control
    1. if, while, for
    2. switch
    3. goto removal
    4. setjmp/longjmp
  9. Primitive Types And Sizes
  10. Math library functions
  11. Date and Time library functions
    1. tm()
    2. time()
    3. asctime()
    4. Processor Times
    5. localtime()
    6. Other date/time functions
  12. Other library functions
    1. rand(), seed()
    2. getpid()
    3. gethostname()
    4. perror()
  13. File Input/Output (IO)
    1. Reading and Writing Objects
    2. runtimeIO
    3. fopen()
    4. fread() and fwrite()
    5. stdin/stdout/stderr
    6. rewind
    7. close(), flush(), remove(), rename()
    8. Error Recovery
    9. ftell()
    10. fseek()
    11. dup(), dup2(), and fcntl()
    12. Low-level IO functions: read(), write(), open(), etc.
    13. tmpnam() and tmpfile()
  14. Low Level IO
  15. Formatting IO
    1. printf()
    2. fprintf()
    3. scanf, fscanf, and sscanf
      1. "Read the whole file" approach
      2. "Non-trivial file format" approach
  16. Arrays
    1. Array Initialization
  17. Error handling
    1. Error Handling in C
    2. Error Handling in Java
    3. No Error Handling Required
  18. Memory management
    1. Primitives
    2. Arrays
    3. malloc()
    4. calloc()
    5. realloc()
    6. free()
    7. memset()
    8. sizeof
  19. Pointers and Addresses
    1. Pointers to Primitives
    2. "Pass by reference"
    3. How to eliminate "*" and "&"
    4. Pointers No Longer Needed
  20. Function Pointers and Reflection
  21. Assertions
  22. Starting a child process
    1. system()
    2. popen()
    3. fork() and exec()
  23. Signal Handling()
  24. Packaging and Directory Structure
  25. Naming Conventions and Code Style
    1. Naming conventions
    2. One declaration per line
    3. Declare variables at their use
    4. Don't do assignment and comparison on one line
  26. Cross-Platform
    1. Platform-specific characters
    2. Primitives are fixed sizes
  27. General cleanup

Preprocessor

There are several phases to C compilation. The first phase is preprocessing, in which the C preprocessor (cpp) is run on your source code. It makes fairly simple syntactic changes. Preprocessor directives begin with "#" and they are line-based: they end at the newline (unless it is escaped). In general, preprocessor directives can appear anywhere in a program, but in practice they almost always appear at the top of a file, and are typically used to define constants. In this section, we cover each of the various preprocessor directives and how to eliminate them to produce Java code.

#define

Constants

final static variable in Java:
...becomes...
public final static int onE = 1;
public final static String HELLO = "hello world";
public final static char LETTER = 'a';
The variable type should be clear from the value. If the value is not a simple type, see the section below on macros. You may also #define without specifying the value. This is so you can later check whether it's been defined via "#ifdef":
If the intent is to enable and disable various code which is either platform-specific or compiler-specific (such as the "UNIX" example above), then the #define can be eliminated and the various alternatives combined, as Java is cross-platform and all compilers work the same. Otherwise, a variable can be created, such as:
public static boolean DEBUGGING_ON = true;
A #define may refer to some other #define:
And, of course, each variable must have the appropriate type:
public final static int MAX_NAME_LENGTH 20;
public final static int MAX_LAST_NAME_LENGTH MAX_NAME_LENGTH;
Note that in many cases, there is simply no need for the constant in Java. For example, lengths of character arrays are no longer needed when you start using Java Strings.

Macro Functions

When the value in a #define is actually more complicated than a simple value, you can create a function for it:
...becomes...
public float TWO_PI() {
    return (2 * 3.14);
}
And people also use #define to actually define a function:
Of course, you can make these functions, but be careful not to obscure your code here. In the case of ABS and HALF above, as well as many other cases:
...by using #define, the code has become less readable, not more. Also note that the need for many #defines will go away as Java already has built-in support. For example, the Math.abs() method calculates an absolute value. There's no need to use a #define for it. Similarly, "boolean" is a built-in type and "true" is a built-in value.
When you change a "#define" into a Java function, sometimes it's not be obvious what the return type should be. If the function is just a single __EXPRESSION__, you'll have to look closely at the last __EXPRESSION__ to determine that type. If the function is a series of statements, then the function should return "void".

Straight Text Replacement

There are some cases where you'll want to do exactly what the C preprocessor does: a simple text replacement. For example, you may have a small chunk of code that you didn't want to keep repeating:
                                        (A1) ^= (A2); \
                                        (A2) ^= (A1); \
                                        (A1) ^= (A2); \
                                }

Unneeded Defines

Any time you have a #define value that's not needed because the functionality is already provided by Java, simply delete the #define and change all references as needed. For example:

#ifdef and #ifndef

C programs often use #ifdef to check for platform and compiler specifics:
...
    #include <unistd.h>
These will simply go away in Java.
Sometimes #ifdef is used to enable/disable debugging:
printf(...);
These are best replaced by a function:
public void debug(String s) {
    if (DEBUG) {
        System.out.println(...);
    }
}
Similarly, when a #ifdef is used to check if a certain feature is turned on or not...
These checks need to be done via a variable or a function in Java:
public final static boolean HAS_SPECIAL_FEATURE = false;
public static boolean hasSpecialFeature() {
    return false;
}
Note that "#if defined(X)" can be used in place of "#ifdef X" and "#if !defined(X)" can be used in place of "#ifndef X".

#if

"#if" has much the same types of use as "#ifdef". Cross-platform and compiler checks such as these go away:
And compile-time checks such as these need to be done at runtime in Java:

#include

Java does not have an "#include". You will need to "import" various libraries that you need, but the most commonly needed classes are in the Java "java.lang" package, which you do not need to import. The contents of files stdio.h, stdlib.h, etc. will be replaced by their Java equivalents (see below), and your own ".h" files will get converted to .java files or eliminated. Simply remove all #includes for now.
In some cases, "#include" is used to keep data in a separate file:
struct person[] people =
...and file "people.data" contains:
{
{"andy", 42},
{"betsy", 41}
}
Obviously, in these cases you'll need to "copy-and-paste" that code from the #include file.

#pragma

The #pragma directive is used to invoke compiler-specific functionality. There is no general rule for what to do with a #pragma line, other than to say "Get rid of it!". Java compilers all conform to the Java Language Specification, and there is no need to write any Java code that depends on a specific compiler.

#error

The "#error" directive is used to force the preprocessor to abort. It's usually used to check for some invalid combination of such combinations or simply remove the checks.

Preprocessor Constants: __LINE__, etc

There are a few pre-defined constants in C:
__FILE__
__LINE__
__STDC__
__DATE__
__TIME__
__FILE__ and __LINE__ are typically used for debugging. In Java, the easiest equivalent is to simply call Thread.dumpStack() to print the entire call stack, including file names and line numbers. __STDC__ has no equivalent, as there is only one Java Language Specification, and all implementations of the compiler and runtime JVM attempt to conform to that spec (there once was a non-conforming VM, but that lawsuit and that VM are ancient history).
__DATE__ and __TIME__ are the date and time of compilation. There simply is no Java equivalent for these. If you really want to know when your code was compiled, you'll have to implement your own mechanism. Remember that we don't have a single executable file in Java, though, we have many .class files.

typedef

Though "typedef" is not a preprocessor directive, it sure looks like one. It's used to simply provide another name for a type:
typedef int AGE;
typedef struct date {
int day;
int month;
} mydate;
In the example above, we can now use "AGE" as a synonym for "int". Simply change all variables to be their true types.
Note that typedef can be used to define a function's return type and it's argument types. For example, here we use typedef to indicate that FUNCTYPE means "function that takes two parameters: a char and a float, and returns an int":
typedef int FUNCTYPE(char a, float b);
FUNCTYPE f;
And similarly, typedef can be used to declare a function pointer type:
typedef int (*FUNCPOINTER)(char a, float b);
FUNCPOINTER fp;
In both these cases, simply remove the typedef and declare the functions as you normally would.
Note that typedefs can refer to one another:
typedef int AGETYPE;
typedef AGETYPE ANIMAL_AGETYPE;
Obviously, you'll want to be sure that both AGETYPE and ANIMAL_AGETYPE are changed to int.

The main() function

Hello, World

When your program takes no arguments (i.e. argc and argv are not referenced), all you need to do is change the signature of your main() function. The Java main() function takes a single array of Strings argument. The classic C "hello, world" program:
int main(int argc, char *argv[]) {
    printf("Hello, World!\n");
}
...becomes...
public static void main(String[] args) {
    System.out.println("Hello, World!");
}
There is no need for argc, as you can get an array's length any time with "args.length()". String is a class, and is much easier to use than an array of characters. The main function must be declared public and static, and it does not return a value. Any "return" in the main function must be changed to "System.exit(n);".

argc And argv

Because argv does not contain the name of the program and there is no "argc" in Java, you may have to make some slight adjustments in your handling of argc and argv. In Java, argv[0] contains the first argument, not the name of the current executable. You can usually just adjust your indexes by one and replace argc by argv.length.
If you don't want to risk touching the main() function, you can simply write another main() function that calls the existing one:
public static void main(String[] args) {
    String[] argv = new String[args.length + 1];
    argv[0] = "MyProgram";
    for (int i = 1;i < args.length;i++) {
        argv[i] = args[i - 1];
    }
    MyProgram instance = new MyProgram();
    System.exit(instance.main(argv.length, argv));
}

getopt

There is no equivalent to the C "getopt()" function in Java. If you really miss getopt(), you could use the GNU Getopt()class.

Syntactic differences

In this section, we'll discuss various simple syntactic differences between C and Java.

Valid Identifiers

There are a few special characters (such as '#') that are valid in C identifiers but not in Java identifiers. If the compiler complains, simply rename the identifier. Identifiers are things like variable and function names.

extern

In C, a variable or function can be declared "extern" to indicate that it's not visible when the individual file is compiled, but only "visible" at link time. Java compilation does not go through a "compile" phase and then a "link" phase. each .java file is compiled into a .class file, and all needed files must be "visible" during this compilation. So simply eliminate the "extern" keyword everywhere.

Parameterless Functions: "void *"

In C, you can declare a function that takes no arguments like this:
int f(void *) {
}
...or even...
int g(void * = 0) {
}
Also, "((void) 0)" can be used in a #define to define an empty function like this:
Simply remove these constructs so that nothing is between the parentheses.

static variables and functions

Also, variables and functions are no longer truly "global"; each one is declared in a particular class. Therefore, you need to use the class name when referencing them. For example, say we have a this in file person.c, which is now the Person class in Java:
int age;
void birthday() {
    age++;
}
Now that you have a true Person object, and a Person can be created with:
Person p = new Person();
All references to "age" would then need to be via a particular Person object ("p" below):
System.out.println(p.age);
On the other hand, if your file just contains a collection of useful methods and isn't really a true object, then you would probably make the methods static. Say "reverse()" is one of several String-manipulation methods in a file called "strfuncs.c":
String reverse(String s) {
    ...
}
The "Strfuncs" class is not a true object as Person was. There are no fields in it and so each method only needs the data it is passed to do its work. Thus, these methods should all be made "static":
public static String reverse(String s) {
    ...
}
And they are called by using the Class name rather than a particular instance:
String r = Strfuncs.reverse("abc");

Conflicting Variables

In C, a local variable can have the same name as another local variable within the same scope (though not at the same "level" - one must be within a sub-block of the other):
int main() {
    int i = 1;
    {
        int i = 2;
    }
}
The Java compiler does not allow this. Simply rename one of the variables.

Missing function and variable types

In C, you can leave off the type in a function or variable declaration, and it's assumed by the compiler to be of type "int". Not so in Java. Anytime the type is missing, choose an appropriate type ("void" is often a better choice than "int").

Access keywords: "public", "private", etc.

In Java, each variable, function, and class is declared to have "public", "private", "protected" access or it may not have any of these three, which is referred to as "package" access. Make everything "private" unless you have a reason not to. Remember from Programming 101: "Global variables are bad."

K&R-style functions

C still supports the old "K&R-style" function syntax:
main(argc, argv)
int argc;
char *argv[];
{
How quaint. The 70's are over. Change them:
main(int argc, char *argv[]) {

Function Declarations

In C, when one file refers to a function that's defined in another file, you need to "declare" that function, often using the "extern" keyword:
extern int myMax(int a, int b);
You never need to declare functions in Java. As long as the function exists at compile time, the code will compile. And as long as the function exists at runtime, no runtime exception will be thrown.

Variable Declarations

Similarly, references to variables outside of a file can be declared with the "extern" keyword. Simply delete these "extern declarations", too.

array declarations

You may not have noticed it, but the way arrays are declared in C is a big strange. This code:
"double v[200];"
Not only says that you have an array of doubles called "v", it also initializes that array to have 200 items, all set to 0.0. In Java, you must be more explicit:
"double[] v = new double[200];"
Note that you could say "double v[]", instead of "double[] v", but please don't. The "double[] v" is clearer, and Java programmers tend to follow this convention very closely, whereas C/C++ programmers do not.

no comma operator

The comma operator in C:
a=3, b=4, c=5;
Is just not there in Java. Just make them individual statements separated by ";".
Also, C allows a comma inside the initialization part of the "for" statement:
for (a=1, b=2, c=3; a != 10; a++) {
Java does not allow this. Move the extra statements out of the "for":
b=2;
c=3;
for (a=1; a != 10; a++) {

Consecutive Strings

C compilers will accept two consecutive strings:
char *s = "a" "b";
The Java compiler will not accept this. Use the "+" concatenation operator:
String s = "a" + "b";

Unused Keywords

Several C keywords are simply not needed in Java.

"signed" and "unsigned" keywords

There are no "signed" and "unsigned" types in Java. Is it really going to kill you to waste a bit? Simply remove all "signed" and "unsigned" keywords.
Also, remove any ending "u" from any constant int variables like this one:
unsigned int i = 27u;

"register" keyword

There is no "register" keyword in Java. Let the runtime virtual machine decide which variables to keep in registers, not the programmer. Trust me, it's better at it than you are. Remove all "register" keywords.

"const" keyword

The "const" keyword can usually be replaced by the Java "final" keyword. A "final" Java variable cannot be assigned a value (except at its declaration), a "final" function cannot be overridden, and a "final" class cannot be subclassed.

Redefined Keywords

The following are keywords in Java, but not in C:
abstract
private
this
boolean
implements
protected
throw
import
public
throws
byte
instanceof
transient
extends
try
catch
final
interface
finally
strictfp
class
native
super
new
package
synchronized
If you have any of these in your C code, you'll need to eliminate them. For example, if you use one of these for a variable name, just change that variable name.

Static Functions

Because C is not object oriented, all functions are essentially "static": function calls are not associated with particular object instances. But in Java, such a function call must be explicitly declared as static. For example, here is a Java call to a sort() function that's in the Sorter.java file:
Sorter.sort(myList);
(You can tell it's a static function call because we use "Sorter", rather than any particular instance of some "Sorter" object). Whenever you see a call such as this, add the "static" keyword to the function declaration. Don't bother adding making the function static unless you need to, such as when a function is only called within the same file.

Type conversions and casting

Java will automatically convert between compatible types, but the compiler will require that you do an explicit type-cast when there may be side effects. For example:
float f = 1.2;
int i = f;
...will cause truncation, so you must show that you really want to do this...
float f = 1.2;
int i = (int) f;
And you certainly can't do type-casts that don't make sense. For example, you couldn't type-cast a Person object to a String or array of ints and then print it out to see the internal layout. Don't bother looking around for places where type casts are needed: just add them where the compiler says they're needed.

VarArgs and "..."

In C, the ellipsis ("...") as a function parameter indicates that the function may take zero or more additional arguments. The constructs that are then used to reference those parameters are va_list, va_start(), and vprintf(). There is no such construct in Java. You should probably write a version of the method for each valid combination of arguments. When you have multiple versions of the same function like this, just have a single function that does all the work and have all the others call it. So writing all those functions that do the same thing is not as much work as you might think.
An alternative is the pass an array of Objects as the last argument. So this:
int f(int a, int b, ...) {
    int sum = 0;
    va_list args;
    va_start(args, b);
    vprintf(args);
    for (i = 0;i < 3;i++) {
        sum += va_arg(args, int);
    }
    va_end(args);
}
...becomes...
    int f(int a, int b, Object[] args) {
    int sum = 0;
    int argsIndex = 0;
    printf(args);
    for (i = 0;i < 3;i++) {
        sum += Integer.intValue(args[argsIndex]);
    }
}

Data Types

In Java, type checking is stricter than in C. A boolean is not an int, and you can't compare a boolean to an int, assign a boolean value to an int, type cast a boolean to an int, etc. Similarly, an Object is different from an int. And char is meant to hold a character (a 16-bit UNICODE value), which is not completely interchangeable with int and short types.

boolean Variables

Any time you have a variable that should really be a boolean, change it's type to "boolean". References where the variable is already being used as a boolean, such as inside an "if" clause, need not change. However, you'll have to change many of the references. Zero and one are replaced by false and true in comparisons and assignments to your variable. If your variable holds values 1 (for true), and -1 (for false), you may have "flag = -flag;", which would change to "flag = !flag;".
Here are some of the replacements that Jazillian makes when changing a variable to boolean:
PatternReplacement
v1 = nullv1 = false
v1 = 0v1 = false
v1 = -1v1 = false
v1 = 1v1 = true
v1++v1 = true
v1 = -v1v1 = !v1
v1 == null!v1
v1 == 0!v1
v1 == 1v1
v1 == -1!v1
v1 != nullv1
v1 != 0v1
v1 != 1!v1
v1 != -1v1
v1 + 1v1

boolean Functions

Just as with variables, functions that return a true/false value should be changed to return a boolean type. Obviously, that will require changes within the function (such as a "return" __EXPRESSION__), and may require changes where the function is called.
Note that many large C projects have a convention that functions should return a flag that indicates success or failure. In Java, the Exception handling mechanism should be used for this.

What type is Zero?

In C, the value "0" is used as a boolean to "false". And 0 (or NULL, or some other some struct, union, enum, etc is set (or compared) to 0, change that 0 to the Java value "null". Specifically, here are some invalid uses of 0:
  • A non-numeric variable is assigned the value 0, NULL, or some other zero-value.
  • A non-numeric variable is compared to the value 0, NULL, or some other zero-value.
  • 0 supplied as an element of array initialization.
  • Return of 0 from a function that returns some non-numeric type.
In all these cases, 0 can be replaced by the Java keyword "null".

char vs. int

In order to save a few bytes of memory, C programmers often use the char type rather than the int type. In Java, you'll want to use short rather than char. Only use char for actually holding individual characters, and use short if you have a small integer.
Here are some of the places where a char variable is valid in C, but not Java:
  • Inside numeric __EXPRESSION__s: "char c; a = b + c;"
  • Array indexes: "char c; a = b[c];"
  • Array assignment: "char[] c = {1, 2, 3};"
  • Assigned or compared to an int value: "char c = 4 + 3;"
When you have a variable that's declared as a char, but used as an int (as in the cases above), the Java compiler will complain, and you should just change the declaration to "int". If use the variable as a char and in some place, but use it as an int in others, you could just put an "(int)" type cast in front of the char usages.

Array Indexes are int

In Java, array indexes must be type int, not short or long.

Loss of Precision

Unlike C compilers, the Java compiler will complain when you've got an assignment that might cause data to be lost due to the variable being a "smaller" type than the assigned value. A simple example:
float f;
int i = f;
The Java compile fail with a "possible loss of precision" error. You need to add an explicit type cast to indicate that you understand that a "float" is larger than an "int", and that the value that "i" gets may not be the exact same value that "f" contains:
float f;
int i = (int) f;

Strings

Java has a built-in String class, whereas C programmers use either an array of chars or a pointer to a char for a string. Change all char arrays and char pointers to type String. While it is possible that you really want an array of chars rather than a String, that would be a very rare case.

The String class

Java has the built-in String class, so a String is not the same as an array of characters or a pointer to a character. You may certainly create a String from an array of characters (or an array of bytes, or another String, etc), and you may certainly copy a String into an array of characters, but the String and the array of characters are two different variables.
The key thing to know about String is that Strings are immutable: they cannot be changed. When we concatenate two strings, for example, we're really creating a brand new String object:
strcat(s1, s2);
...becomes...
s1 = s1 + s2;
Here, the "+" operator creates a new String object, copies characters from s1 and s2 into it, and returns the object. It just so happens that here we've made the "s1" object be this new String. We could also have used the shorthand operator:
s1 += s2;
Just to reiterate...
WARNING: "strcat(s1, s2);" is not exactly the same as "s1 = s1 + s2". After the C strcat() function, s1 still points to the same memory location. But after the Java String concatenation "+" operator, s1 points to a different location.
The String class has a built-in equals() method that returns a boolean to indicate whether the String is character-for-character the same as the given String. So:
if (strcmp(s1, s2) == 0)
...becomes...
if (s1.equals(s2))
The String.compareTo() method is similar: it returns -1, 0, or 1, depending on which String is "greater".
The String.indexOf() method returns the index of the given character or String (or -1 if it's not found):
String s = "abcd";
int i = s.indexOf('b');    // returns 1
int j = s.indexOf("cd");    // returns 2
int k = s.indexOf('z');    // returns -1
Another very useful String method is substring():
String s = "abcd";
String cd = s.substring(2);    // returns "cd"
String b = s.substring(1, 2);    // returns "b"
Do not use "==" to compare two Strings. Use the equals() method. The C functions such as strspn(), strpbrk(), strstr(), etc could all be duplicated exactly with a few lines of Java code, but your code will end up simpler than it is today if you use the String methods indexOf(), substring(), etc directly.
As you start using the Java String object, you'll be surprised to find out that you rarely need to ever actually copy characters from one location to another. Simply having many String objects all pointing to the same memory location is the norm in Java and, surprisingly, that's usually what you want. So while the table below shows the C code:
strcpy(s1, x1);
...and says that the Java equivalent is:
s1 = x1;
It's important to note that these two are, in fact not doing the same thing. The strcpy() function is allocating memory and copying characters, while the "s1 = x1;" Java code is simply making s1 point to the same location as x1. That sounds scary, but it turns out that almost always, your code will work as you want it to! I know, you're very skeptical. Trust me.

charAt

The String.charAt() method gives you access a particular character of the String. Change all the ways of referencing a particular character to use charAt().
char *s;
char a = s[5];
char b = *s;
char c = s + 4;
...becomes...
String s;
char a = s.charAt(5);
char b = s.charAt(0);
char c = s.charAt(4);
And for two-dimensional arrays of chars:
String[] argv;
char a = argv[0][1];
...becomes...
String[] argv;
char a = argv[0].charAt(1);

No setCharAt() function

There is no setCharAt() method in String. Strings are immutable in Java. If you really want to change an individual character, you have to build up a new instance of the String and assign your variable to this instance. For example, to convert the first character to uppercase:
String s = "andy";
s = Character.toUpper(s.charAt(0)) + s.substring(1);
Because it can be very involved to rewrite code in this way, Jazillian provides a CStringUtils.setCharAt() runtime method.

String Functions

Most of the C string functions have simple Java String equivalents:
String Functions
DescriptionC functionJava equivalent
Concatenatestrcat(s1, s2)s1 += s2
Compare: equalitystrcmp(s1, s2) == 0s1.equals(s2)
Compare: non-equalitystrcmp(s1, s2) != 0!s1.equals(s2)
Compare: find largerstrcmp(s1, s2)s1.compareTo(s2)
Compare: find largerstrcoll(s1, s2)s1.compareTo(s2)
Copystrcpy(s1, x1)s1 = x1
Substring excluding charsstrcspn(s1, s2)*
lengthstrlen(s1)s1.length()
Compare n charsstrncmp(s1, s2, n1)s1.substring(0, n1).compareTo(s2.substring(0, n1))
char excluding charsstrpbrk(s1, s2)*
last occurrence of stringstrrchr(s, c)*
Substring including charsstrspn(s1, s2)*
Search for substringstrstr(s1, s2)*
*Items marked with a star would require more than a single line of Java code. If you want to know exactly how you would write an equivalent in Java, see the CStringUtils class in Jazillian.
However, before you think that perhaps your Java code may be more complicated than C code in these cases, that is rarely the case. For example, the Java equivalent of strncmp() shown above looks fairly complicated. However, if you look at a typical usage of strncmp(), you'll probably find that there's a simpler way to do it in Java:
strncmp (name, "/dev/tcp/", 9);
...becomes...
name.startsWith("/dev/tcp/");
As you'd expect, the String class has very many other useful methods, such as lastIndexOf(), startsWith() and endsWith(), equalsIgnoreCase(), trim(), toLowerCase() and toUpperCase(), and several regular-__EXPRESSION__ processing functions. The charAt() function returns the character at a particular index, but there is no setCharAt() method: Strings are immutable.
Because Java Strings are immutable, how you deal with them in Java is often quite different than in C. You almost never need to make multiple copies of a String, for example, because many variables can all point to the same String with the assurance that that String can never be changed somewhere else in the program. This will take some getting used to if you're new to Java. Replace all the various string-copying function calls by simple assignments:
C FunctionJava Function
strcpy(v1, x1)v1 = x1
strcpy(v1 = v2 = x0, x1)v1 = x1; v2 = v1
strcpy(v1 = x0, x1)v1 = x1
strdup(v1)v1
strncpy(v1, x1, v2)v1 = x1

Character Functions

Most of the character-related functions have equivalent static functions in the Java Character class. Unlike the String class, the Character class doesn't have much real functionality, other than to provide the following static functions:
String Functions
DescriptionC functionJava equivalent
Convert to Lowercasetolower(c1)Character.toLowerCase(c1)
Convert to Uppercasetoupper(c1)Character.toUpperCase(c1)
is alphanumericisalnum(c1)Character.isLetterOrDigit(c1)
is a letterisalpha(c1)Character.isLetter(c1)
is a control characteriscntrl(c1)Character.isISOControl(c1)
is a digitisdigit(c1)Character.isDigit(c1)
is a graphical characterisgraph(c1)c1 > '\u0020' && c1 < '\u007E' && !Character.isSpaceChar(c1)
is lowercaseislower(c1)Character.isLowerCase(c1)
is a printable characterisprint(c1)( c1 > '\u0020' && c1 < '\u007E')
is punctuationispunct(c1)( c1 > '\u0020' && c1 < '\u007E' && 
!Character.isSpaceChar(c1) && !Character.isLetterOrDigit(c1))
is whitespaceisspace(c1)Character.isWhitespace(c1)
is uppercaseisupper(c1)Character.isUpperCase(c1)
is a hex digitisxdigit(c1)Character.isDigit(c1) || ( Character.toLower(c1) >= 'a' && Character.toLower(c1) <= 'f')
The Java equivalent of the C memchr() function is non-trivial, so it's provided as a Jazillian runtime function:
C FunctionJava Function
memchr(v1, v2)CStringUtils.memchr(v1,v2)

null String Termination

In C, every string should be terminated by a NULL ('\0') character. In Java, there is no such termination character. A String does have a particular length, but you never have to deal with the hassle of plugging in a NULL at the end, searching for the NULL, or stripping off the NULL.

Data Structures

Java has no "struct", "union", or "enum" constructs, only classes.

struct

struct Becomes a Class

A C struct simply becomes a Java class that has only fields, no methods:
struct person {
    int age;
    char *name;
}
...becomes...
class Person {
    int age;
    String name;
}

Initialization

In C, when you declare a struct variable, memory is allocated and fields are initialized. In Java, when you declare a class variable, it's set to null and no object is created. To create an object, use the "new" keyword, so:
person fred;
...becomes...
Person fred = new Person();
In C, you can initialize the struct like this:
person fred = {27, "Fred"};
You can't use that syntax in Java (it's inherently bad, as it relies on the order of field declarations within the struct). Instead, you would need to create a constructor:
class Person {
    private int age;
    private String name;
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
...and then call the constructor:
Person fred = new Person(27, "Fred");
Note that in C, you don't need to supply a value for all the fields. For example, if we leave off the name field like this:
person fred = {27};
...the name field will get its default value. This, of course, is very bad programming style and very error prone. During translation to Java, Jazillian will warn you when it encounters such cases.

Unnamed Structures

In C, you can have a structure that doesn't have a name:
struct {
    int age;
    char *name;
} p;
Here, we have a variable "p" that has "age" and "name" fields, but we haven't named the struct (a typical name would be "person" here). Java has an equivalent called an "inner class", but during translation the cleanest approach is to just give the class a name.
Note that you can even have nested unnamed structs:
struct {
    int age;
    struct {
        lastname;
        firstname;
    };
}
Again, just give both structs a name.

union

a "union" is like a "struct", except the union data structure can hold various types of data at various times. They are often used within a struct which contains a flag that indicates what the union is holding. For example:
union appendages {
    int numLegs;    // for mammals
    int numFins;    // for fish
}
struct animal {
    int fishOrMammal;    // tells what 'legs' holds
    appendages legs;
}
The easiest thing to do is simply make each union a class, and it will all work fine. But that would waste space, and more importantly, it would be confusing. Instead, use subclassing:
class Animal {
}
class Mammal extends Animal {
    int numLegs;
}
class Fish extends Animal {
    int numFins;
}
There's no need for the "fishOrMammal" flag, because you could always use the "instanceof" operator if you needed to:
if (v instanceof Mammal)
    ...

enum

A C enum is used to specify a set of valid values for a variable. Java has no enum construct, but it's easy enough to create one.
enum marriage_status = {MARRIED, SINGLE, DIVORCED};
...becomes...
class MarriageStatus {
    public final static MarriageStatus MARRIED = new MarriageStatus();
    public final static MarriageStatus SINGLE = new MarriageStatus();
    public final static MarriageStatus DIVORCED = new MarriageStatus();
}
Alternatively, you could define these constants to be of type "int", but then you would be bypassing some nice type-checking. These constants are then referenced like this:
married = MarriageStatus.SINGLE;

Passing the Java Compiler

The Java compiler is stricter than the C compiler. If you've ever tried to compile your code with a C++ compiler or the lint tool, you know that the C compiler tends to be a bit too forgiving.

Uninitialized Variables

If it's possible to reference a local variable before you've ever assigned it a value, the Java compiler will give you a compile error. The Java compiler is doing what's called "control flow analysis" to find such cases. In that case, simply assign the variable a value at its declaration. If you want all the gory details, there is entire chapter in The Java Language Specification titled "Definite Assignment" about this issue.

Unreachable Statements

The Java compiler will also detect statements that can never possibly be reached, and give an error. Simply remove or comment out such statements.

No Static Local Variables

Local variables in Java can never be declared static. If the compiler complains about such variables, simply move the declaration outside of all methods in your class.

Flow of Control

if, while, for

The "if", "while", and "for" constructs are virtually identical in Java as compared to C. There is one thing to keep in mind, though: In Java, boolean is a built-in type, so the __EXPRESSION__ inside an "if" must evaluate to a boolean, not an "int". The same goes for the "while" __EXPRESSION__, and the middle __EXPRESSION__ in a "for".
int x = ...;
if (x) {
}
while (!x) {
}
for (x = 10; x; x--) {
}
...becomes (changes are shown in red)...
int x = ...;
if (x != 0) {
}
while (x == 0) {
}
for (x = 10; x>0; x--) {
}
Because the middle condition in a "for" statement needs to be a boolean, you may no longer leave it blank:
for (i=0; ; i++)
...becomes...
for (i=0; true; i++)
and
for (;;)
...becomes...
while (true)

switch

The "switch" construct is identical in Java and C: the __EXPRESSION__ must be of type "int", "byte", "char", "short", or "long", just as in C.

goto removal

Well, we've had it pretty easy up until this point. Java does not have a "goto" statement, and if you have "gotos" in your C code, it's going to take some work to get rid of them. If you just have a few "gotos", you may be able to easily restructure the code to eliminate them. The "goto-eliminate" problem has been studied for decades and there are automated ways to eliminate them.
Jazillian uses the algorithm described in Ana M. Erosa and Laurie J. Hendren, "Taming Control Flow: A Structured Approach to Eliminating Goto Statements," in Proceedings of the 1994 International Conference on Computer Languages, Toulouse, France, pp. 229-240, IEEE Computer Society Press, May 16-19, 1994. ). Basically, each "goto" is moved closer and closer to its label in a series of steps, until they are next to each other and can be eliminated. This algorithm has been modified by Jazillian to take advantage of the fact that Java does have "labeled breaks and continues". For example, you can do this:
start:
if (...) {
    for (...) {
        break;    // breaks out of "for"
        break start;   // breaks out of "if"
    }
}

setjmp/longjmp

The "setjmp" statement is used to record a program's state, and "longjmp" is used to restore the program to that state. The same feat can be accomplished more cleanly with the Java Exception mechanism:
void caller() {
    if (setjmp(x) == 0) {
        callee();
    }
    else {
        printf("an error occurred");    // we got here via longjmp
    }
}
void callee() {
    if () {
        longjmp(x);
    }
}
...becomes...
void caller() {
    try {
        callee();
    }
    catch (Exception e) {
        printf("an error occurred");
    }
}
void callee() {
    if () {
        throw new Exception();
    }
}

Primitive Types And Sizes

Java has the following primitives: boolean, char, byte, short, int, long, float, double. There is no "unsigned" and there is no "long long". Unlike C, the sizes of these types are fixed - they do not depend on the hardware, operating system, or runtime environment. The following table shows the Java primitives:
TypeContentsDefaultSizeMinimumMaximum
booleantrue or falsefalse1 bit
charUnicode\u000016 bits\u0000\uFFFF
bytesigned int08 bits-128127
shortsigned int016 bits-3276832767
intsigned int032 bits-21474836482147483647
longsigned int064 bits-92233720368547758089223372036854775807
floatIEEE 7540.032 bits+-3.40282347E+38+-1.40239846E-46
doubleIEEE 7540.064 bits+-1.79769313486231570E+308+-4.94065645841246544E-324
Java programmers rarely use "byte" and "short" and only rarely use "long". Unless you're worried about squeezing every last byte of memory size out of your program, you could just change "byte" and "short" to "int".
Certainly, everywhere you have an "int" variable which you use as a boolean, you should change to "boolean" type.
Note that "char" is 16-bit Unicode, not 8-bit ASCII. However, the ASCII character set is a "subset" of Unicode, meaning that the Unicode characters \u0020 through \u007E are equivalent to the ASCII and ISO8859 (Latin-1) characters 0x20 through 0x7E. This means that most character operations, such as these, will still work:
    x > 'a' && x < 'z'
    lower = upper - 'A';

Math library functions

Almost all of the functions declared in "math.h" are provided as static methods in the Java Math class:
Trig Functions
DescriptionC functionJava equivalent
Arc cosineacos()Math.acos()
Arc sineasin()Math.asin()
Arc tangentatan()Math.atan()
Arg tangent of x/yatan2()Math.atan2()
Cosinecos()Math.cos()
Hyperbolic Cosinecosh()Java has no Math.cosh
Sinesin()Math.sin()
Hyperbolic Sinesinh()Java has no Math.sinh
Tangenttan()Math.tan()
Hyperbolic tangenttanh()Java has no Math.tanh
Exponents and Logarithms
Exponentexp()Math.exp()
Fraction and Exponentfrexp()Java has no frexp function
Multiple by 2^nldexp(v, n)Just use: (v * pow(2, n))
Natural loglog()Math.log()
Log base 10log10(x)Java has no Math.log10()
Integer and Fractionmodf(n1, &n2)Use v1 = Math.floor(n1); n2 = n1 - v1;
Raise to powerpow()Math.pow(
Square rootsqrt()Math.sqrt()
Ceilingceil()Math.ceil()
Absolute valuefabs()Math.abs()
Floorfloor()Math.floor()
Remainderfmod()IEEEremainder()

Date and Time library functions

tm()

The "struct tm" contains a date/time, and it's Java equivalent is the Date class. Here are the fields of "struct tm" and their equivalent Date methods:
tm_secgetSeconds()
tm_mingetMinutes()
tm_hourgetHours()
tm_mdaygetDate()
tm_mongetMonth()
tm_yeargetYear()
tm_wdaygetDay()

time()

The time() function returns the current time as a long since the Epoch (Jan. 1st, 1970). The units may be milliseconds or may be something else, depending on your system. See the CLOCKS_PER_SEC or CLK_TCK variable on your system. The Java equivalent is System.currentTimeMillis(), which returns the time since the Epoch in milliseconds.

asctime()

The asctime() function produces the date formatted as a string. Happily, the Date.toString() method returns the exact same format as asctime(), so:
struct tm d = ...;
printf(asctime(v));
...becomes...
Date d = ...;
System.out.println(d);

Processor Times

The "struct tms" data structure and clock() and times() functions relate to the CPU time used by the current process. This information is not available in Java. Typically, though, these are used to determine how long a particular chunk of code takes to execute, which you can also do easily in Java:
long startTime = System.currentTimeMillis();
...code to be measured...
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
The difftime() function is a very handy function that would do this subtraction for you. Wow.

localtime()

The localtime() function will convert a given time (in "long" format) to a "struct tm", while converting to the local time zone. In Java, the Date class holds a "universal" date/time, while the Calendar class is used to get locale-specific information. For example, the "tm_yday" field of "struct tm" contains local the day-of-year.
long t;
time(&t);
struct tm now = localtime(t);
printf("today is day number %d\n", now.tm_yday);
...becomes...
Date now = new Date();
Calendar cal = Calendar.getInstance();    // get instance for default locale
cal.setTime(now.getTime());
System.out.println("today is day number " + cal.get(Calendar.DAY_OF_YEAR));

Other date/time functions

The stime() and settimeofday() functions set the system time: the time of the local machine. You can't do this in Java. Similarly, the adjtime() and adjtimex() functions adjust the system clock.

Other library functions

rand(), seed()

The rand() function returns a random integer, and the seed() function is used to seed the random number generator (typically with the process id or current time) so you don't always get the same sequence of numbers. The java.util.Random class does the same thing, but provides nextBoolean(), nextInt(), nextLong(), nextFloat(), and nextDouble() for generating various types of random values. You can provide a seed, but you don't need to: the default Random constructor uses the current time as a seed.
seed(getpid());
int r = rand();
...becomes...
Random generator = new Random();
int r = generator.nextInt();
If you have several calls to rand(), you only need to create a single Random object, and you could just create it once like this:
private final static Random random = new Random();

getpid()

There is no easy way in Java to get the current process id. Often, the process id is only used as a random number generator seed as shown above.

gethostname()

The java.net.INetAddress class represents an internet address. It has a static getLocalHost() method which returns the INetAddress for the local machine and it has a getHostName() method which returns the name. So:
char name[100];
gethostname(name, x);
...becomes...
String name = INetAddress.getLocalHost().getHostName();

perror()

The perror() function simply prints an error, and so should be replaced with System.err.println().

File Input/Output (IO)

Java provides a rich set of file IO classes in the java.io package. For starters, you can simply replace "printf" with "System.out.println": See the "printf" section under "Formatting IO" below. Here, we deal with the rest of the IO functions.
First, a quick introduction to File IO in Java. Java has a Reader class that contains methods like read() to read a single character. Reader has several subclasses: FileReader to read a file, BufferedReader to buffer input, etc. Typically, to read a file and do buffered (line-by-line) reading (for efficiency), you create a FileReader, and wrap it with a BufferedReader. And you then go ahead and read the contents, and close the file when you're done:
BufferedReader reader = new BufferedReader(new FileReader("infile"));
String line = reader.readLine();
while (line != null) {
    line = reader.readLine();
}
reader.close();
As you'd expect, writing is similar:
PrintWriter writer = new PrintWriter(new FileWriter("outfile"));
writer.writeln("hello");
reader.close();
As you may have guessed, System.in is a variable of type BufferedReader and System.out and System.err are of type PrintWriter.
In C, you have a single "FILE" type, and you have to be careful that the operations you perform (read/write) match up with the access privileges you opened the file with ("r", "w", etc). With Readers and Writers, there is no such potential for error. Java does provide a RandomAccessFile object in case you want to both read and write and do other fancy things, but usually it's not needed.

Reading and Writing Objects

In C, the typical way to store and retrieve data involves manually storing information about the size of data. For example, to store an array of ints, you might write out the number of items first, and then the data. To read back in, you read the number of items, and then only try to read that many items. That's tedious, but it may be the easiest way to get existing C code working in Java. There's an easier way in Java. Using the Java Serialization feature, you simple write out a whole Object (an array is considered an object here), and later read the whole thing back in.
However, you may already have your data on disk and you might not want to change the storage format. In that case, you'll need to be able to read and write data in Java in the same way as you did in C. This can be difficult because there is no "sizeof" operator in Java. One approach would be to have each class know how to write itself out, field by field, and read itself back in.

runtimeIO

If you're simply reading and writing entire objects (structs, arrays, etc), it would be nice if you had a Java class that knew how to read and write these objects in the same format as C. In other words, provide the Java serialization feature, but store objects in "byte-format" that matches the format that C data is stored. Jazillian provides such classes. Jazillian changes your code to call these classes, and so of course they are part of your runtime code. The classes are DataObjectInputStream and DataObjectOutputStream and they provide methods such as:
    public Object readObject(Object object);        // read a whole Object
    public Object readArray(Object array, int numElements);  // read an array
    public String readLineAndNewline()  // read up to newline: fgets()
    public int readIntChars(); // read an integer: fgetw()
    public void rewind();
    public void pushback();    // "unread" one byte

fopen()

All "FILE *fp" declarations and fopen() calls need to be replaced by the creation of some Reader or Writer (or perhaps RandomAccessFile as a last resort) object as shown above. By creating the object, the file is being opened. Note that you'll need to catch the FileNotFoundException when creating a Reader or Writer.

fread() and fwrite()

Calls to fread() and fwrite() need to be replaced by equivalent calls to one of the various read() and write() methods in the particular Reader or Writer class that you're using.
Not that in Java, you almost never have to read data byte-by-byte as you do in C. For example, to read a single line from a text file, you might do this in C:
char c;
char line[20];
for (c = line;(*c = getchar()) != '\n';) {
    if ( *c == - 1) {
        continue ;
    }
    else {
        if (c != v2 || *c != ' ') {
            c++;
        }
    }
}
That code can be replace by:
String line = stdin.readLine();
(with the only difference that "line" would not contain the newline character, which you'd probably strip off anyway).

stdin/stdout/stderr

System.in is equivalent to stdinSystem.out is equivalent to stdout, and System.err is equivalent to stderr.

rewind

There is no rewind() function in Java. To go back to the start of the file, you would have to close the file and open it again.

close(), flush(), remove(), rename()

The close() method is in the Reader and Writer classes, so simply change:
fclose(fp)
...to...
fp.close();
(Of course, you'll want a better variable name than "fp").
Similarly, flush() is a method in Writer that replaces fflush().
To remove a file, use the delete() method in the File class:
remove("myfile");
...becomes...
File myFile = new File("myfile");
myFile.delete();
Similarly, use the renameTo() method to rename a file. The clearerr() method just isn't needed.

Error Recovery

There is no clearerr() equivalent in Java. The various IO methods can throw various exceptions on error. For example, the FileReader constructor throw a FileNotFoundException if the file doesn't exist and all the various write() functions can throw an IOException if they are unable to write to the file. You'll typically have to wrap all your IO activity in a try/catch block, where you catch IOException.

ftell()

The ftell() function returns the current position within an open file. Typically, it's used to determine the length of a file by first going to the end of the file and then calling ftell(). You can do the same in Java with this:
File f = new File(fileName);
int length = f.length();

fseek()

fseek() is used to move to an arbitrary location within a file. You can't do this in Java, but there are easy ways to do the things you'd typically use fseek() to do.
DescriptionC fseek() callJava equivalent
To move to the beginning of the filefseek(s1, 0, 0)rewind(s1)
Move to n chars from start of filefseek(s1, n, 0);rewind(s1); fp.skip(n);
go to end of file in preparation for calling ftell()fseek(s1, 0, 2);(see above)

dup(), dup2(), and fcntl()

The dup() and dup2() functions are used to duplicate file descriptors. These are typically used with fcntl to redirect stdin, stdout, or stderr to another file. This can be done more simply in Java by calling setIn(), setOut(), or setErr() in the System class.
fcntl() can also be used to get and set various flags associated with an open file to change how IO is done with that file (such as blocking/nonblocking, appending). Java does not support these.

Low-level IO functions: read(), write(), open(), etc.

In addition to the higher-level fread(), fopen(), etc. C supports low-level IO via read(), write(), open(), etc. As with the higher-level functions, simply replace these with their high-level Java counterparts. This also goes for low-level character and string reading/writing: getc, putc, gets, puts, etc.

tmpnam() and tmpfile()

The tmpname() function generates a temporary file name and tmpfile() creates a temporary file. Is that really so hard that we need our programming language to do it for us?
private static int tmpCount;
...
String tmpName = "tmpFile" + tmpCount++;

Low Level IO

In addition to the higher level IO functions described above, C provides a set of low-level IO functions for very fine-grained control of files and devices. There is no direct low-level Java equivalent, there are ways of doing what you want to do:
If you...Do this
have no compelling reason to use low-level IOUse high-level IO
need to control a serial or parallel portUse the optional Java Comm package.
are buffering file input for performanceDo buffering in Java also
using select() to read from multiple inputsSee the Java NIO package.
Jazillian provides a LowLevelIO runtime class that provides most of the functionality of the Low-Level IO C library. It has methods such as:
  • open(), close()
  • read(), write()
  • ioctl_set(), ioctl_get()
  • tcflush(), tcgetattr(), tcsetattr(), cfsetispeed(), cfsetospeed()
  • select()

Formatting IO

printf()

The System.out variable corresponds to "stdout". Its class is PrintWriter, which has a print() method that takes any Object as its argument and prints the object. It also has a print() method for each of the primitive types. And for each print() method, there's a corresponding println() that appends the (platform-specific) newline character. How canprintln() be smart enough to know how to print any object? Well, calls the toString() method on the object, so you must write a method called toString() in each of your classes if you want to print out that class using print() and println():
class Person {
    private String name;
    private int age;
    public String toString() {
        return "name=" + name + " age=" + age;
    }
}
Replace each printf() call with one or more System.out.print() calls. Take out embedded newline characters; use System.out.println() instead. Pass a single argument to System.out.println(), typically a String created with the "+" operator. If either operand of the "+" operator is a String, it will convert the other operand to a String.
float f = 1.0;
int d = 2;
char *s = "string";
char c = 'a';
person p = ...;
printf("f=%f d=%d\ns=%s c=%c p=\n", f, d, s, c);
...becomes...
float f = 1.0;
int d = 2;
String s = "string";
char c = 'a';
Person p = ...;
System.out.println("f=" + f + " d=" + d);
System.out.println("s=" + s + " c=" + c + " p=" + p);
If you must do number formatting (e.g. "%3.2f"), use the NumberFormat class:
printf("%3.2f", f);
...becomes...
DecimalFormat myFormat = new DecimalFormat("###.##");
System.out.println(myFormat.format(f));
Note that number formatting is an internationalization issue, which the DecimalFormat class handles.
Note that if you have an __EXPRESSION__ as a printf() argument, you may have to enclose it with parentheses:
printf("%d %d", 2+3, 4+5);
...becomes...
System.out.print((2+3) + (4+5));

fprintf()

For fprintf(), also replace with print() and println(), but of course use the object that you call these methods on is no longer System.out, but whatever variable represents some open file.

scanf, fscanf, and sscanf

"Read the whole file" approach

Calls to scanf(), fscanf(), and sscanf() are sometimes not as straightforward. Because these functions take multiple pointers as arguments, they sometimes be replaced by multiple Java statements. One simple approach when starting with Java is to simply read the entire file and store its contents in a String first:
public class FileUtils {
    public static String fileToString(String fileName) {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        StringBuffer buffer = new StringBuffer();
        String line = reader.readLine();
        while (line != null) {
            buffer.append(line);
            buffer.append('\n');
            line = reader.readLine();
        }
        reader.close();
        return buffer.toString();
    }
}
If your input file uses a single field separator (such as a space, comma, or newline), then you can use a StringTokenizer to parse it:
FILE *fp = fopen("myfile", "r");
double numbers[100];
for (i=0; i<100; i++)
    scanf (" %lf", &(numbers[i]));    // note the space before the percent sign
...becomes...
String contents = FileUtils.fileToString("myfile");    // read whole file in - see above
double numbers[] = new double[100];
StringTokenizer st = new StringTokenizer(contents);
for (i=0; i<100; i++)
    numbers[i] = Float.parseFloat(st.nextToken());
Note: in Java, you tend to not have to hard-code any maximums, such as 100 above. This means you also don't have to waste space (such as when you have less than 100 items) and keep track of how many items you have (See the section on Arrays for more details). For example, to read all the tokens in a file:
String contents = FileUtils.fileToString("myfile");
StringTokenizer st = new StringTokenizer(contents);
double[] numbers = new double[st.countTokens];
int i = 0;
while (st.hasMoreTokens()) {
    numbers[i++] = Float.parseFloat(st.nextToken());
}

"Non-trivial file format" approach

If your file has a more complicated format, you'll have to write a little code to parse it. For example, say each line of the file looks like this:
name:address!age
...where ":" and "!" are separators and "name", "address", and "age" are three fields of data on a line. You could parse it like this:
BufferedReader reader = new BufferedReader(new FileReader("myfile"));
String line = reader.readLine();
while (line != null) {
    int colon = line.indexOf(':');
    int bang = line.indexOf('!');
    String name = line.substring(0, colon);
    String address = line.substring(colon+1, bang);
    String ageString = line.substring(bang+1);
    int age = Integer.parseInt(ageString);
    line = reader.readLine();
}
reader.close();
In addition to the StringTokenizer class, there is also a StreamTokenizer class that may come in handy when parsing files.

Arrays

Array Initialization

We can't put array initialization just anywhere in Java; it has to be at the variable declaration. In Java, this is valid...
int[] a = {1,2,3};
...and this is valid...
int[][] a = {{1,2,3}, {4,5,6}};
...but this is not...
int[] a;
a = {1,2,3};
...and you can't just put an array initializer into a method call, so this is not valid either:
class Person {
    String name;
    int[] nums;
    Person(String name, int[] nums) {
    }
}
Person p = new Person("andy", {1,2,3});
In Java, you need to use a slightly different syntax to create such an unnamed array:
int[] a;
a = new int[] {1,2,3};
Person p = new Person("andy", new int[] {1,2,3});

Error handling

Error Handling in C

Many C functions return a special value when an error occurs, and sometimes also set a global variable ("errno") to indicate what the error was. For example, fopen() returns 0 and sets variable errno on error. Some of the functions that return -1 on error are: open(), kill(), iconv_open(), iconv(), waitpid(), creat(), ioctl(), mmap(), fcntl(), dup(), remove(), mkdir(), pipe(), select(), fork(), fcntl(), malloc(), gettimeofday(), clock(), time(), stime().

Error Handling in Java

First, let's cover the basics of exception handling in Java. When a method encounters an error, it throws some Exception, and it's up to the calling function to catch the Exception to handle the error. If a method only throws Exceptions which are subclasses of RuntimeException (OutOfMemoryError, for example), the calling code need not catch it...the code will compile and execution will halt at runtime if the exception occurs. On the other hand, non-RuntimeExceptions (such as IOException) must be caught by the caller, or the code won't compile.
Below are several patterns to look for in your C code, and the corresponding usage of try/catch, using fopen() as an example:
DescriptionC error handling patternJava try/catch equivalent
Check for success
fp = fopen();
if (fp != -1) {
    success();
}
try {
    fp = fopen();
    success();
}
catch (Exception e) {
}
Check for failure
fp = fopen();
if (fp == -1) {
    failure();
}
try {
    fp = fopen();
}
catch (Exception e) {
    failure();
}
If success else failure
fp = fopen();
if (fp != -1) {
    success();
}
else {
    failure();
}
try {
    fp = fopen();
    success();
}
catch (Exception e) {
    failure();
}
If failure else success
fp = fopen();
if (fp == -1) {
    failure();
}
else {
    success();
}
try {
    fp = fopen();
    success();
}
catch (Exception e) {
    failure();
}
We only list "Exception" above, which would work, but it's good coding practice to catch only the specific Exception that your calling function actually throws.
As you can imagine, there are many variations on these patterns. The code may check for less-than-zero rather than -1, may use a "switch" instead of an "if", or may check for success or failure someplace after the actual "fopen" statement.

No Error Handling Required

Some of the C library functions return error conditions that happen so infrequently that it's not worth doing error handling. For example, printf() returns the number of arguments that it printed, but virtually no programmer checks this return value. Similarly, Java's System.out.println() call could throw a RuntimeException, but no one ever bothers to enclose it in a try/catch.
If Jazillian detects a case where no handling is done, but probably should be, it gives a warning.

Memory management

Perhaps the biggest benefit to using Java over C is the ease of memory management. In this section we discuss how to convert C memory allocation and deallocation code to Java.

Primitives

For primitives, memory is allocated the same way in Java as in C, so the following code is unchanged:
int i;    // allocates space for an integer, sets it to 0, and names it "i"
float f = 1.2;    // allocates space for a float, sets it to 1.2, and names it "f"

Arrays

Space for arrays is typically allocated in one step in C, but takes two steps in Java. The C statement:
int[100] i;
creates an array named "i" and allocates space for 100 "ints", setting each to 0. But the Java statement:
int[] i;
...creates an "array" object named "i", but it's current value is null. "int[100] i" or "int i[100]" are not syntactically valid in Java. Referencing i[0] at this point would throw an exception. You need to allocate space with:
i = new int[100];
And, as you'd hope, you can combine the two steps:
int[] i = new int[100];
Since "int" is a primitive, we now have an array of 100 "ints", each initialized to zero. However, had we been dealing with a an Object (i.e. a non-primitive), they would be initialized to null:
Person[] mob = new Person[100];
We now have an array of 100 "Person" objects, each element of the array is set to null. You then need to allocate for the objects explicitly:
for (int i=0; i < mob.length; i++) {
    mob[i] = new Person();
}

malloc()

Space for a new object (an object is anything other than a primitive) can only be allocated with the "new" keyword. So this:
struct person p = malloc(sizeof(struct person));
...becomes...
Person p = new Person();
The "new" operator allocates enough space for a "Person" object and creates a pointer "p" pointing to that space. All fields of "p" are initialized as you'd expect: booleans set to false, numbers to 0, and other objects to null.

calloc()

calloc() is used to allocate space for multiple objects. Often, people just multiply the size of the object by the number of items requested and pass that product to malloc() rather than bother with calloc(). This C code:
struct person people[] = malloc(10 * sizeof (struct person));
...becomes...
Person[] people = new Person[10];
Keep in mind that objects in Java are all really pointers. So "people" is now an array of 10 pointers, each set to null. To actually allocate space for 10 Person objects and make these point to them, we need to add this code:
for (int i=0; i<10; i++) {
    people[i] = new Person();
}
So you need to explicitly add this initialization code in Java, where you didn't need to in C. If it's not obvious where to put this initialization, you can add it to the static block of code in the class. This will ensure that the initialization occurs before any reference.
Obviously, any type cast preceding the malloc/calloc should just be removed.

realloc()

realloc() increases an array's size. Assume a is an array of type "char":
a = realloc(a, 3 * sizeof(char));
...becomes...
char[] tmp_a = new char[3];
System.arraycopy(p, 0, tmp_p, 0, p.length);  // fill up new array with old data
a = tmp_a;
Important note: I you ever find yourself having to increase an array's size, you should certainly not be using an array. Arrays (at least in Java) are meant to only hold a fixed number of objects. Instead, use a List, part of the Java Collections Framework.

free()

There is no need for free() in Java. When an object is no longer referenced by any other object, it is freed up by the garbage collector. You can simply remove all calls to free() from your code. If you're worried that a variable will never go out of scope, or worried that some other object might still keep referencing it, or you just don't really trust the automatic garbage collection much, you could set the object to null to be sure that it gets garbage collected.

memset()

There is no exact equivalent of memset() in Java. memset() is typically used to set data to all zeros after a malloc() because that memory will contain garbage. This is not the case with Java. As discussed above, all variables are initialized (to zero for numbers, false for booleans, and null for objects) on declaration.

sizeof

sizeof is almost exclusively used as an argument to a malloc-type function, so replacing the malloc() calls by "new" as described above should eliminate most sizeof references. If you are really curious about how much space an object takes up, you would have to write some code that uses Reflection to figure it out.

Pointers and Addresses

It's often said that "Java has no pointers". In fact, everything (other than primitives) is a pointer in Java. In other words, objects are always accessed "by reference", never "by value". So given this code:
Person a = new Person();
Person b = a;
a.age = 12;
"a" and "b" are pointing to the same memory, so setting a.age to 12 has also set b.age to 12. If you actually want b to be a copy of a, you would have to write some sort of "copy" function (typically called "clone()" in Java) which copies each field.

Pointers to Primitives

There is no simple Java equivalent to this simple C code:
void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
You might be tempted to try to use the Java Integer class, which is a wrapper around the "int" primitive, but even that won't work, as there is no way to change the value that a given Integer object contains.
All I can offer here is a few rules of thumb about how to get around the lack of pointers to primitives:
  • If you are passing a pointer to a function, have the function return the value instead.
  • If your function needs to return multiple values, go ahead and package the return values into a class.
Look at this minor inconvenience as the price you pay for never having to debug stray pointer problems ever again.

"Pass by reference"

In Java, Objects are passed to functions "by reference", but those references are passed "by value". This means that if we have this code:
Person p = new Person();
p.age = 12;
birthday(p);
...
void birthday(Person p) {
    p.age++;
    p = new Person();
    p.age = 40;
}
copy of the pointer "p" was passed to the "birthday" function. So after the birthday() call, p.age is indeed 13. The "p = new Person();" statement is making the copy pointer point to some new memory location, and "p.age=40;" sets the value at that location to 40. At the end of the birthday() function, that memory location with the 40 is no longer referenced and may be garbage collected.

How to eliminate "*" and "&"

C programmers use pointers in the following ways:
  • As an actual object reference. For example, say we have a linked list and we have a pointer to the "current" object in the list. This is an easy case in translating to Java, because the Java items (such as the items in our linked list) are often Objects, rather than primitives. In that case, the "*" pointer syntax can just be removed: all Objects are pointers in Java. If the items are primitives, they can be wrapped in Objects ("Integer i = new Integer(2);", for example) and the pointer syntax removed.
  • As an index into a data structure. For example, say we have:
    struct person people[20];
    struct person *p;
    
    In this case, "p" can simply be changed to be an index into the array, rather than a pointer.
  • Usage of pointer syntax in place of array syntax. As you many know, pointers really work the same way as arrays under the covers. If you have a pointer that's being assigned a value via malloc() or calloc(), for example, it probably should just be an array. In these cases:
    int *p;
    
    ...becomes...
    int[] p = {0};
    
As mentioned above, if you're using "&" to pass a primitive to a function which will change its value as a side effect, you need to change the function to return the value instead. If the function only sets the value and doesn't use it's initial value, don't even pass it as an argument.
Next, for each pointer variable, determine whether the variable is really an array of objects (space is allocated for multiple objects), or it's really just an index into some other array of objects (such as when you do pointer arithmetic on it). If it's truly an array, go ahead and change it to be an array, replacing "malloc()" with "new". If it's truly an index, change it to an int (not a float - Java array indexes must be int). So this code:
struct person *people = malloc(100 * sizeof (struct person));
struct person *p = &people[0];
for (i=0; i<100; i++) {
    p->age = 3;
    p++;        // make p point to next person
}
...becomes...
Person[] people = new Person[100];
for (i=0; i<100; i++) {
    people[i] = new Person();    // must initialize pointers, as discussed previously
}
for (i=0; i<100; i++) {
    people[i].age = 3;
}
Note that it's generally easier and better to use the generic List object, part of the Collections Framework, rather than arrays. But if you're just learning Java, stick to arrays while eliminating pointers - things will be confusing enough.
C programmers may use pointer arithmetic to determine the index of a particular Object in an array. The base of the array is subtracted from a pointer into the array:
Person[] people = { ... };
int index(void * ptr) {
return ptr - people;
}
One Java equivalent is: Arrays.asList(people).indexOf(p)

Pointers No Longer Needed

Because Java is typically at a higher level of abstraction than C (meaning that it provides most of the functionality you'll typically need), the need for pointers often just disappears as you simplify your code to use built-in Java constructs. For example, the following C function displays a given prompt to the user and then reads an integer, printing an error if it gets a non-integer:
get_int(register char *prompt)
{
        reg int         num;
        reg char        *sp;
        char            buf[257];
        for (;;) {
          for (;;) {
                printf(prompt);
                num = 0;
                for (sp = buf; (*sp=getchar()) != '\n'; sp++)
                        if (*sp == -1)  
                                continue;
                break;
          }
            if (sp == buf)
                    continue;
            for (sp = buf; isspace(*sp); sp++)
                    continue;
            for (; isdigit(*sp); sp++)
                    num = num * 10 + *sp - '0';
            if (*sp == '\n')
                    return num;
            else
                    printf("I can't understand that\n");
        }
}
...but the Java equivalent is just:
int get_int(String prompt) {
    while (true) {
        System.out.print(prompt);
        String line = System.in.readLine().trim();
        try {
               return Integer.parseInt(v1);
        }
        catch (NumberFormatException e) {
              System.err.println("I can't understand that");
        }
    }
}
By using readLine() rather than reading one character at a time, we've eliminated the need for a pointer. And by using Integer.parseInt() to rather than building up our own int a character at a time, we've also eliminated the need for a pointer.
The general rule is that if you're writing code that you think someone else must have written at some point (such as code to prompt the user and read an answer), you probably shouldn't be writing that code; Java probably provides an easier way.

Function Pointers and Reflection

Java has no function pointers, but the same functionality can be accomplished with the Reflection feature. In general, Reflection lets you find out information about object classes at runtime. You can find out everything about a class's fields and methods, and even set and get field values and invoke methods.
Say you have a table that indicates which function should be called in various cases such as this:
String[][] nextInLife = {
    // age  function to call
    {"10", "gotoMiddleSchool"},
    {"13", "gotoHighSchool"},
    {"18", "gotoCollege"},
    {"22", "getAJob"},
    {"65", "retire"}
}
You can use this table to invoke the appropriate function like so:
void callFunction(String age, Person p) {
    String methodName;
    // lookup the right method in the table
    for (int i=0; i<nextInLife.length; i++) {
        if (nextInLife[i][0].equals(age)) {
            methodName = nextInLife[i][1];
            break;
        }
    }
    Class clazz = p.getClass();
    // find the method that takes no args
    Method method = class.getMethod(methodName, new Class[]{});
    // call the method on p, passing no args
    method.invoke(p, new Object[]{});
}

Assertions

The C assert() call maps directly to the java "assert <__EXPRESSION__>" construct. When using the "assert" feature of Java, keep in mind:
  • Assertions where added to JDK version 1.4.
  • Source must be compiled with the "source 1.4" flag to avoid compile errors
  • The "java" executable must be run with the "-ea" flag to enable assertions
  • An AssertException is thrown when the assertion fails, which dumps the stack and exits - similar to what happens in C.

Starting a child process

system()

The simplest way to start another process in C is with the system() call. Simply pass the string of the executable and any arguments. The Java Runtime class has several exec() methods that do the same thing. You get an instance of Runtime via the static getRuntime() method. So:
system("/bin/ls");
...becomes...
Runtime.getRuntime().exec("/bin/ls");

popen()

The C popen() function executes a command and reads its input or output stream. The Runtime.exec() methods return a Process object, and you can get the process input and output streams from that:
s1 = popen("mycommand", "r");
...would be replaced by...
Process process = Runtime.getRuntime().exec("mycommand");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

fork() and exec()

The more complicated way to start a child process in C is to call fork() to create a child process which is identical to the current one, and then call exec (in the child process) to overlay that process with something else. This code:
int pid = fork();
if (pid == 0) {
    exec(cmd);
}
else if (pid == -1) {
    // error handling
}
else {
    // parent code
}
...becomes...
try {
    Runtime.getRuntime().exec(cmd);
}
catch (Exception e) {
    // error handling
}
There is a threading problem in the above Java code, however. The exec() call will not return until the child process finishes. To have execution continue in the parent without waiting for the child to finish, use a separate thread by changing:
    Runtime.getRuntime().exec(cmd);
...to...
Runnable r = new Runnable() {
    public void run() {
        Runtime.getRuntime().exec(cmd);
    }
};
r.start();
Look up multithreading in any Java book for more details.

Signal Handling()

The C signal() method allows you to handle signals passed to your program from outside. The most common use of signal() is to catch SIGTERM or SIGINT and either ignore these outside request to abort the program, or to do some cleanup before exiting. Java supports this sort of thing via the Shutdown Hooks API.
You can also write a C signal handler and hook it into your Java program. See Signal Chaining.

Packaging and Directory Structure

Typically, C source code is contained in a directories such as:
  • src - C source code (.c files)
  • include - C header files (.h files)
  • bin - executables and script files (.exe, .sh, .bat, etc)
  • lib - libraries (.o, .a files)
Java applications do not usually follow this convention. For starters, there are no include files, there are no executables, and there are no libraries. There are only source files (.java) and class files (.class), and the class files are typically packaged into JAR file (.jar).
Java source files are grouped into directories logically by function, and when compiled, each .class file is placed in the same directory as it's .java source file. Each .java file is in a "package", and the package structure matches the directory structure. Each .java file has a "package" line as the first line that indicates what package it's in. Products typically put their company name and product name in the package names, too. So, for example, you may have grouped all database-related classes together into a package, and you may have a DBRecordLookup.java file, which has this as its first line:
package mycompany.myproduct.database;
And then the file DBRecordLookup.java must be in a directory that ends with "mycompany/myproduct/database".
If you're converting C code to Java, the easiest approach is to ignore Java packages at first. Every Java class will be in the "default" package, and you won't have to worry about where things are yet. Then later after you've got it compiling correctly, go back and split it into packages. Classes from one package will need to "import" classes in other packages.
As a general rule, you should have one Java class per file. Other than "anonymous inner classes", it's best to stick to this rule while getting started with Java.

Naming Conventions and Code Style

As you start to look at Java code, you'll notice a stark contrast with most C code: Java programmers actually follow naming and style conventions! Really! It will seem awkward at first to be spelling out complete words for variable names, but you quickly get used to it and start to appreciate it. When a coworker tells you to call function "set minimum age", you can be sure it's setMinimumAge(), not set_min_age() or sma() or SetMini() or whatever. Change all variable and function names to follow the conventions early on, and your life will be a lot easier. If you have counter variables with names like "i", don't worry - Java programmers do that too.

Naming conventions

The naming conventions for variables, functions, and classes is slightly different in Java:
  • Classes are mixed case, starting with uppercase: "PotentialEmployee"
  • variables and methods are mixed case, starting with lowercase: "firstEmployee", "getAge()"
  • constants are all uppercase with underscores: "MINIMUM_AGE"
  • everything is always fully spelled out: "spellOutEveryWordPlease"

One declaration per line

For some reason, Java programmers tend to declare each variable on its own line:
int i, j;
...becomes...
int i;
int j;
It's just more readable.

Declare variables at their use

In C (at least older versions), you had to declare your variables at the start of your function. This is not good because the larger a variable's scope, the harder it is to maintain. In Java, just declare the variable where you first need it, even inside a "for":
int i;
int j;
...
for (i=0; i<10; i++) {
    for (j=0; j<i; j++) {
    ...
    }
}
...becomes...
...
for (int i=0; i<10; i++) {
    for (int j=0; j<; j++) {
    ...
    }
}

Don't do assignment and comparison on one line

Assigning a variable and checking its value can be done all in one __EXPRESSION__ in both C and Java. But Java programmers tend to separate them out to make it more readable:
if ((fp = fopen(...)) != 0)
...becomes...
fp = fopen();
if (fp != 0)
(Of course, we'll later replace fopen and fp with their Java equivalents).

Cross-Platform

C is "platform independent" or "portable", which means you can get it working on one platform, and then "port" it to other platforms by making various platform-specific changes. Java is "cross-platform", which means you write the code once, and that code (if done right) will work on all platforms. Yes, it may not work perfectly, there are many issues here. But the point is that you don't have a "port to platform X" on your development schedule, only "test on platform X". In this section, we describe how to make platform-specific constructs platform-independent.

Platform-specific characters

The newline character ('\n', '\r\n', etc) and path separator (':', ';', etc) varies between platforms. The Java libraries are designed so that they handle these differences. So, for example, you could say:
File f = new File("/usr/bin/ls");
and this will work on any platform (on Windows, for example, it would change the forward slash to backslash and use the current drive). In the rare case where you do want to know what the path separator is, you can get it via a "system property" called "path.separator". You can also get the newline character, the name and version of the operating system, etc.
So there should be no work to do on this issue. If you have different processing for different platforms, eliminate all but one. Of course, this only applies to the core Java language. If you use a GUI toolkit, a database package, or some other package that's got different versions for different platforms, you'll have to deal with them.

Primitives are fixed sizes

A large part of what makes Java "cross-platform" is the fact that the primitives are fixed sizes, independent of hardware. That just means that if you're holding large values in your variables, it's important that you change them to a Java type that's big enough. This is usually not a problem though, as Java's 32-bit "int" and 64-bit "long" tend to be at least as wide as whatever you're currently using. See the Primitive Types section for the list of primitive sizes.

General cleanup

During a conversion to Java, you may want to consider doing some general cleanup of the code. Some of these items where covered in more detail earlier.
  • Group source files in some logical way.
  • Remove unused variables, functions, and files.
  • Remove unused argument parameters.
  • If a global variable is only used within a function, move the declaration into the function.
  • Remove "dead code" which is never reached.
  • Make global variables local whenever possible.
  • Use more meaningful variable and function names.
  • Remove incorrect or useless comments. Many comments that made sense for the C code may no longer make sense.
  • Add any comments that are badly needed.
  • Format the code in a consistent style.
  • Use braces where they are optional (such as a "while" statement containing only one statement)
  • Only do one assignment per line (i.e. split up "a = b = c = 0;" into 3 statements)
  • Remove empty files. By the time you're done, many of your C files (including all headers) should be empty!



출처 : http://joyholic.kr/273