This section describes how to pass values of basic types, such as int, char, double, and so on, between Java and C++ programs.
The ability of the Java virtual streams to exchange information with C++ programs is based on correspondences between the Tools.h++ abstract base classes RWvistream and RWvostream and the Java interfaces VirtualInputStream and VirtualOutputStream.
Every member function for reading or writing a basic type or an array of a basic type in the C++ virtual stream classes has a corresponding method in the Java virtual stream interfaces. It is crucial that you read data with the method appropriate to both the data that was written and the way it was written, as shown in Table 7 and Table 8.
C++: RWvistream | Java: VirtualOutputStream |
get() |
putChar(char) |
get(char&) |
putChar(char) |
get(wchar_t&) |
putWChar(char) |
get(unsigned char&) |
putUnsignedChar(char) |
get(char*, size_t) |
putChars(char[],int) |
get(double*, size_t) |
putDoubles(double[],int) |
get(float*, size_t) |
putFloats(float[],int) |
get(int*, size_t) |
putInts(int[],int) |
get(long*, size_t) |
putLongs(long[],int) |
get(short*, size_t) |
putShorts(short[],int) |
get(wchar_t*, size_t) |
putWChars(char[],int) |
get(unsigned char*, size_t) |
putUnsignedChars(char[],int) |
get(unsigned int*, size_t) |
putUnsignedInts(long[],int) |
get(unsigned long*, size_t) |
putUnsignedLongs[](long[],int) |
get(unsigned short*, size_t) |
putUnsignedShorts(int[],int) |
getString(char*, size_t) |
putString(String,int) |
operator>>(char&) |
insertChar(char) |
operator>>(double&) |
insertDouble(double) |
operator>>(float&) |
insertFloat(float) |
operator>>(int&) |
insertInt(int) |
operator>>(long&) |
insertLong(long) |
operator>>(short&) |
insertShort(short) |
operator>>(wchar_t&) |
insertWChar(char) |
operator>>(unsigned char&) |
insertUnsignedChar(char) |
operator>>(unsigned short&) |
insertUnsignedShort(int) |
operator>>(unsigned int&) |
insertUnsignedInt(long) |
operator>>(unsigned long&) |
insertUnsignedLong(long) |
C++: RWvostream | Java: VirtualInputStream |
put(char) |
char getChar() |
put(wchar_t) |
char getWChar() |
put(unsigned char) |
char getUnsignedChar() |
put(const char*, size_t) |
char[] getChars(int) |
put(const double*, size_t) |
double[] getDoubles(int) |
put(const float*, size_t) |
float[] getFloats(int) |
put(const int*, size_t) |
int[] getInts(int) |
put(const long*, size_t) |
long[] getLongs(int) |
put(const short*, size_t) |
short[] getShorts(int) |
put(const wchar_t*, size_t) |
char[] getWChars(int) |
put(const unsigned char*, size_t) |
char[] getUnsignedChars(int) |
put(const unsigned int*, size_t) |
long[] getUnsignedInts(int) |
put(const unsigned long*, size_t) |
long[] getUnsignedLongs[](int) |
put(const unsigned short*, size_t) |
int[] getUnsignedShorts(int) |
putString(const char*, size_t) |
String getString() |
operator<<(char) |
char extractChar() |
operator<<(double) |
double extractDouble() |
operator<<(float) |
float extractFloat() |
operator<<(int) |
int extractInt() |
operator<<(long) |
long extractLong() |
operator<<(short) |
short extractShort() |
operator<<(wchar_t) |
char extractWChar() |
operator<<(unsigned char) |
char extractUnsignedChar() |
operator<<(unsigned short) |
int extractUnsignedShort() |
operator<<(unsigned int) |
long extractUnsignedInt() |
operator<<(unsigned long) |
long extractUnsignedLong() |
When mapping basic types between C++ and Java, one important issue concerns the ranges of values. In Java the ranges are fixed, but not so in C++. Because the ranges of values for the basic types in C++ are implementation-defined, in general, we can't be sure that there is a basic type in Java with the same range of values for each basic type in C++, or the reverse.
Table 7 and Table 8 show how we have attempted to map basic types to reduce the chance of problems. For example, the Java method VirtualInputStream.getUnsignedInt()returns a long because most C++ implementations use a 4-byte int, and such an unsigned value could be too large for the 4-byte Java signed int. When we can determine at run time that an inappropriate value is being written or read, we throw respectively an OutputRangeException or an InputRangeException as defined in package com.roguewave.vsj.
Another important issue for mapping basic types is that of character encoding schemes, such as ASCII, EBCDIC, Latin-1, Unicode, etc. Java uses the Unicode encoding, which uses 2 bytes for each character. Characters with a zero-valued high-order byte have low-order bytes equivalent to the Latin-1 character set, which is itself a superset of the ASCII encoding. From Table 7 and Table 8 you can see that C++ wchar_t wide characters are mapped to the Java char type. This works fine as long as the C++ program uses the Unicode encoding. If not, you may have to do your own translations to get the results you want. Similarly, mapping a C++ char to a Java char may give surprising results if the C++ program uses EBCDIC characters and the Java program uses ASCII!
Of course, to do any real work you need more than C++ abstract base classes or Java interfaces. In both languages, you eventually need concrete implementations of these. Virtual streams for Java provides concrete implementations PortableInputStream and PortableOutputStream that correspond to the Tools.h++ classes RWpistream and RWpostream.
The following code shows how to write an int from a C++ program and read it into a Java program.
The C++ Program
#include <rw/rstream.h> #include <rw/pstream.h> int main() { // attach an RWpostream to standard out: RWpostream pstr(cout);
int x = 11; pstr << x;
cerr << "Wrote an int with value " << x << endl; }
The Java Program
import java.io.IOException; import com.roguewave.vsj.PortableInputStream; public class ReadInt { static public void main(String[] args) { // attach a PortableInputStream to standard in: PortableInputStream pstr = new PortableInputStream(System.in);
try { int x = pstr.extractInt(); System.out.println("Read an int with value " + x); } catch (IOException e) { System.out.println("Problem reading int. \nCaught: " + e); } } }
See the Tools.h++ documentation for instructions on compiling and linking the C++ program with Tools.h++. To compile the Java program, make sure that the path of packages com.roguewave.vsj and com.roguewave.tools.v2-0 is included in your CLASSPATH environment variable.
> javac ReadInt.java # compile the Java program > writeInt > int.dat # run the C++ program Wrote an int with value 11 # (output) > java ReadInt < int.dat # run the Java program Read an int with value 11 # (output)
When reading basic types from Java, you must be prepared to catch an instance of java.io.IOException. This exception may be thrown for several reasons:
The underlying stream from the java.io package throws an IOException.
The end-of-file marker is reached unexpectedly.
Unexpected characters or symbols are encountered.
The value in the stream is out of range for the data type being read.
For example, if you try to read an int from a file with bad data, you might get something like the following:
> echo bad data > bad.dat # create a file of bad data > java ReadInt < bad.dat # run the Java program on the bad data Problem reading int. # (output) Caught: java.io.IOException: Expected digit or '-'. Found: 0x62
Note that 0x62 is the ASCII hex value for the character b.
In this next example, we write an array of doubles from Java and read them in C++.
The Java Program
import java.io.IOException; import com.roguewave.vsj.PortableOutputStream;
public class WriteDoubles { static public void main(String[] args) { // attach a PortableOutputStream to standard out: PortableOutputStream pstr = new PortableOutputStream(System.out); double[] dvals = { 3.14, 1.414, 2.718 };
try { pstr.putDoubles(dvals, 3); System.err.println("Wrote three doubles: { " + dvals[0] + ", " + dvals[1] + ", " + dvals[2] + " }"); } catch (IOException e) { System.out.println("Problem reading int. \nCaught: " + e); } } }
The C++ Program
#include <rw/rstream.h> #include <rw/pstream.h> int main() { // attach an RWpistream to standard in: RWpistream pstr(cin); double dvals[3]; pstr.get(dvals,3); cout << "Read three doubles:\n" << dvals[0] << '\n' << dvals[1] << '\n' << dvals[2] << endl; }
Compile both programs, then type:
> java WriteDoubles > jbl.dat # run the Java program Wrote three doubles: { 3.14, 1.414, 2.718 } # (output) > readDoubles < dbl.dat # run the C++ program Read three doubles: # (output) 3.14 1.414 2.718
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.