Limitation of CINT Cint accepts most of K&R and ANSI C/C++ language construct but not perfect. In fact, Cint is not aimed to be a 100% ANSI/ISO compliant C/C++ language processor. It rather is a portable script language environment which is close enough to the standard C++. This document describes major differences from the standard. # General information: + How to workaround Cint limitation If you have unsupported features in your source code, that part must be escaped by "#ifndef __CINT__" for cint and "#ifndef __MAKECINT__" for makecint. The macro __CINT__ is defined both in cint and makecint. __MAKECINT__ is defined only in makecint. + Simple expression recommended Because ANSI/ISO C++ standard is a huge document, it is impractical to describe every details of differences in this document. Only major differences and cautions are described. To avoid unnecessary confusion, please use simple expression whenever possible. # Scope: + Function scope Variables can be declared in global or function scope. Unlike ANSI, local variable has function scope. If a local variable is once declared in a function, it will be alive until execution gets out from the function even if it is declared within sub-block. In ANSI C, local variables have block scope. void func() { int i; for(i=0;i<10;i++) { int n; /* block scope */ printf("n=%d\\n",n++); } /* n is still alive here in cint, n should be already dead in ANSI C */ } + In function typedef and class declaration/definition You can not define a new type in a function neither with typedef or class/struct declaration. void func() { typedef int int32; // BAD in cint class A { /* ... */ }; // BAD in cint } # Fundamental types + long long , unsigned long long 'long long' is supported by an optional library which can be compiled in lib/longlong. There are some platforms which can not compile this library. 'long long' is implemented as a wrapper class G__longlong with limited capability. 'unsigned long long' is simply handled as 'long long'. Cint will not distinguish between 'long long' and 'unsigned long long'. + bool 'bool' is supposed to be a fundamental type in C++ standard. But in Cint, bool is defined as enum in $CINTSYSDIR/include/bool.h. boo.h is automatically loaded by cint when it sees declaration using bool. In most cases, it works without problem. There is a known problem, however, if you check bool with ERTTI API. #include <ertti.h> #include <iostream.h> int main() { G__TypeInfo t("bool"); if(t.Property()&G__BIT_ISFUNDAMENTAL) { // this is supposed to be true, but not in cint cout << "bool is a fundamental type" << endl; } if(t.Property()&G__BIT_ISENUM) { // cint takes this case cout << "bool is an enum" << endl; } return(0); } # Pointer declaration When declaring pointer, space character is needed somewhere in the declaration. For example, int* p1; // OK int *p2; // OK int * p3; // OK int*p3; // Cint parsing limitation, space character needed This is Cint limitation. For pointer to pointer, cint may not understand too many levels of redirection. If you have many levels of pointer redirection, it is recommended to have space character between type name and '*'. int ****p4; // OK int**** p5; // Cint parsing limitation # Class/struct alignment: Each C/C++ compiler or interpreter has unique class/struct alignment and padding rule. When class or struct is precompiled, cint mirrors compiler's alignment. Alignment of precompiled class/struct is identical to compiler you use. If class or struct is interpreted, cint uses very conservative alignment and padding rule which may not match to other C/C++ processing system. # bit-field: Bit-fields in precompiled class and struct can not be accessed from the interpreter. # Variable argument: Variable argument is supported from Cint 5.14.69. <stdarg.h> must be included to use variable argument. Cint accepts both form of declaration. void foo1(char *fmt, ...); void foo2(char *fmt ...); Above declarations are handled identically. Function is mached only by name. Types and number of arguments are not used as function mathcing criteria. + Calling interpreted function with variable arguments A function with variable arguments can be interpreted by the Cint interpreter. For doing this, va_list, va_start, va_arg and va_end can be used. For example, #include <stdio.h> #include <stdarg.h> void foo2(char *fmt ...) { va_list ap; va_start(ap, argn); for(int i=0;i<argn;i++) { double d = va_arg(ap,double); printf("%g ",d); } printf("\n"); va_end(ap); } + Calling compiled function with variable arguments Argument values for variable arguments must be put into function call stack. For each computer platform, specific byte layout must be emulated by Cint. Because byte layout is not publicly informed, this capability may not be portable to all platforms. At this moment, this capbility is only supported for Intel architecture(Linux & Win32), HP-UX and Solaris. Support for PowerPC looks quite difficult, if not possible. Need more investigation for other platforms. + ANSI C library functions In order to suport variable argument, cint needs to know stack layout which is machine dependent and not known. Cint supports following library functions as special cases. Please note that scanf function has limitation in number of arguments. ostream& ostream::format(char *format ...); int fprintf(FILE *fp,char *format ...); int printf(char *format ...); int sprintf(char* string,char *format ...); int fscanf(FILE *fp,char *format ...); // only upto 12 arguments int scanf(char *format ...); // " int sscanf(char *string,char *format ...); // " # switch statement and default: label Cint requires default: label to appear at the end of switch statement. If you put case label after default: , switch statement does not work properly. For example, int n = 1; switch(n) { case 0: printf("zero\n"); break; case 1: printf("one\n"); // 'one' is printed both with cint and g++ break; default: printf("many\n"); break; } switch(n) { case 0: printf("zero\n"); break; default: printf("many\n"); // Cint prints 'many' break; case 1: printf("one\n"); // But g++ prints 'one' break; } # Library function: + ANSI C library function Most of ANSI C standard library functions are built in. However, following ones are not supported. int setjmp(jmp_buf environment) void longjmp(jmp_buf environment,int rval) typename *va_arg(va_list listptr,typename) void va_end(va_list listptr) void va_start(va_list listptr,type rightparm) int vfprintf(FILE *fp,const char *format, va_list arguments) int vprintf(const char *format, va_list arguments) int vsprintf(char *string,const char *format, va_list arguments) + Optional POSIX, Win32, TCP/IP libraries Cint does not contain non ANSI functions by default. But you can use them by building optional libraries. Small subset of POSIX, Win32 and TCP/IP libraries can be build under lib/posix, lib/win32api and lib/socket directory. Please read README.txt in each directory. + STL Cint source package comes with an old STL (HP reference implementation) which is in stl directory. You can interpret string, vector and list containers and several generic algorithms. Small subset of precompiled STL containers can be built under lib/dll_stl directory. Read lib/dll_stl/README.txt and run setup script there. You can precompile STL containers by yourself too. Simple example is in demo/makecint/stl directory. STL dummy headers are in lib/prec_stl directory. Please understand that there are many limitations for using STL on Cint. STL is so complex that it is very difficult to document all limitations. # Operator: + Power operator Power operator '@' is the original extension. It can be used both integer and floating point. This extension is made for convenience of scientific application. Before cint5.15.25, '**' notation was also used as power operator. This extension has been eliminated in order to avoid confusions in following expression. int a=1,b=2,c; int *p = &b; c = a**b; // Use parenthesis a*(*b), although completely legal + sizeof Sizeof must be used with '()'. If size of and its' operand is separated by space , without '()', cint will not produce correct result. Cint returns 0 for sizeof unnamed union if it is precompiled. If the code is interpreted, Cint can return appropriate number. + '.*' and '->*' Pointer to member access operator '.*' and '->*' are newly supported from cint5.14.9. You need to define G__PTR2MEMFUNC macro in platform dependency file in order to turn this feature on. Use of pointer to member access operator is not recommended because it is premature. + Unsupported operators Sequencing operator ',' is not supported. Operation of ',' is hard coded in Cint core and can not be modified by operator overloading. Also, expression like 'expr1,expr2,expr3' does not work properly. # Array declaration Cint supports array declaration. There are original enhancements and recommendations. + constness of array dimension Variable dimension is not allowed in C/C++. Cint has special capability to allow it only in interactive command and '{ ... }' style macro. void f() { int n=5; float a[n]; // this is error now } $ cint cint> . cint> int n=5; cint> float a[n]; // this is allowed, special extension + constness of array dimension - recommendation Constness is not enough for valid array dimension. C/C++ requests array dimension to be defined in following ways. int g() { return 5; } #define n0 5 // GOOD: macro recommended int n1=5; // BAD : non-const static static int n2=5; // BAD : non-const file-scope static const int n3=5; // GOOD: static const recommended const int n4=g(); // BAD : static const initialized for process void f() { int n5=5; // BAD : non-const static int n6=5; // BAD : non-const static const int n7=5; // GOOD: static const not recommended static const n8=5; // GOOD: static const not recommended const int n9=g(); // BAD : non-static const float a[n?]; } Looks pretty inconsistent, but this is C++. All of above behaviors are implemented in cint5.14.5. Having array dimension constant in local scope works properly, but it complicates the situation. It has to be "static const" anyway , it is recommended to declare it in global scope. + constness and staticness of array Following code works on cint. But if you try to be safe, const or static array in local scope is not recommended. const int nx=5; const float ax[5]={1,2,3,4,5}; // Recommend this void f() { const int n=5; // not recommended float a1[n]; // This is fine const float a2[n] = {1,2,3,4,5}; // not recommended static float a3[n]; // not recommended static const float a4[n]={1,2,3,4,5}; // not recommended } # Preprocessor statements: Cint has limitations in handling define macros in default mode. Following limitations applies. You can avoid following limitations by using preprocessor prior to interpretation by -p or +P,-P command line option. Read also cint(1) for use of -p and +P,-P options. + Macro definition: The biggest syntax limitation of cint is associated with define macro. Cint can only handle simple define macros. Some complex use of macros has to be handled by separate preprocessor by -p or +P,-P options. #define ON 1 /* Fine */ #define f(x) (x-1) /* OK, but not recommended */ #define bool int /* OK, but not recommended */ #define DECL_B int b /* May not work */ # Operator overloading + Unsupported operators for overloading Following operators can not be overloaded. new , delete , unary & The operator new is already overloaded in cint as follows. So, you don't need to overload new anyway in the interpreter environment. This is already done for both interpreted and precompiled classes. void* operator new(size_t size,void* arena) {return(arena);} + Explicit operator function call Operator function can not be called explicitly by name because of parse rule limitation. complex a=complex(1,5),b=complex(-1,3.1),c=complex(0,0); c = operator+(a,b); // BAD operator function can not be called // explicitly. c = a+b; // OK # operator= overloading In Cint, if you define operator= for a class, class that is derived from it must have operator=. In ANSI/ISO standard, this is not necessary. class A { public: A& operator=(const A& x); }; class B : public A { public: B& operator=(const B& x); // this is needed in cint }; # Templates Template works probably better than most of UNIX based C++ compilers, but not as good as Windows based ones. Cint can run simple STL programs. Following limitations applies. + Explicit type conversion Explicit type conversion for template class can not be used because of parsing limitation. Use typedef if you want to do so. // suppose you have ary<double,100> a; a = ary<double,100>(3.14); // can't handle this + Scope resolution operator Template class name can not be used with scope operator to resolve ambiguity. Use typedef if you want to do so. intary10.ary<int,10>::disp(); // can't handle this + Member function template Member function template works in Cint with limitation. Member function template must be defined within a class definition as inline function. template<class T> class A { T dat; public: template<class E> A(E& x) { dat = x; } // OK template<class E> void Set(E& x) {dat=x;} // OK }; + Partial template specialization Partial template specialization is not supported. For example, // this template is fine template <class Iterator> struct iterator_traits { typedef typename Iterator::iterator_category iterator_category; typedef typename Iterator::value_type value_type; typedef typename Iterator::difference_type difference_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; }; // template partial specialization not supported template <class T> struct iterator_traits<T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; }; # STL Supporting templates and supporting STL are quite different subject. STL is a very complex template library which many compiler makers have trouble with. Cint supports STL in limited way. + Using precompiled STL containers vector, list, deque, map and string container classes can be precompiled if they are instantiated. Please refer to lib/prec_stl/README.txt and lib/dll_stl/README.txt for more detail. It is recommended to use precompiled STL containers rather than interpreting them. + Interpret STL containers Cint can interpret vector, string and some simple list container classes. But this is not recommended. It is very slow and has many troubles. Interpreted STL implementation is based on old 1994 HP reference implementation. # Reference member Reference type member is not supported class A { private: int& refa; // Limitation }; # Reference to pointer to pointer Reference to pointer to pointer is not supported int** &a; // Limitation # Array reference Array reference is not supported by Cint. void func(int (&ary)[5]); // Limitation # Function overloading Cint implements function overloading resolution. It behaves quite similar to what is defined in ANSI/ISO standard, but not 100% correct. If you find strange behavior, it is recommended to remove ambiguous function calls. Some of those limitations are described below. + Pointer to function as argument Cint has problem resolving function overloading with pointer to function as an argument. Suppose you have following functions, void f(int (*p2f)(double)); void f(void *p); Cint may not resolve above functions correctly. This is due to Cint's complication of handling pointer to interpreted function and pointer to compiled function. # Pointer to function It is recommended to avoid pointer to function in interpreted code whenever possible. Implementation of pointer to function is very slow. + Mixing interpreted and compiled pointer to function In many cases, user wants to mix interpreted and compiled pointer to function. Interpreted pointer to function is not compatible with compiled pointer to function. There is a special trick to do so. Please refer doc/ref.txt for the detail. Search for the item G__isinterpretedp2f and read it carefully. Please limit use of such trick to where it is inevitable. # Pointer to member + Pointer to member functioin Pointer to member function is newly supported from cint5.14.9. This feature is normally turned off. In order to activate, you need to define G__PTR2MEMFUNC macro in platform dependency file and re-compile Cint. This feature is only experimental and not recommended for use in general. Interpreted pointer to member function and compiled pointer to member function are completely different objects. Mixing those concepts will cause fatal error. For example, following code works as long as everything is interpreted. However, it will cause fatal error if you precompile g() and interpret main(). class A { public: void f() { } }; typedef void (A::*A_p2mf)(void); void g(A *pa,A_p2mf x) { (pa->*x)(); } main() { A a; A_p2mf pf = &A::f; (a.*pf)(); } + Pointer to data member Pointer to data member is not supported. # Exception handling Exception handling is implemented but with limitations. Object destruction may not be done properly in complex case. It is recommended not to use Exception Handling in interpreted code. For example, if you interpret following code, Cint will crash at ~A() because Cint can not handle object destruction if exception is thrown in a constructor. class A { int *d; int s; public: A(int sz) : s(sz) { if(s<0) throw exception(); d = new int[s]; } ~A() { delete[] d; } // causes problem here }; void f() { A a(3); A b(-1); // exception is thrown A c(4); } int main() { try { } catch(exception& x) { printf("This is a std::exception '%s'\n",z.what()); } return 0; } Workaround to this problem is to either precompile class A , or to change implementation of class A as follows. class A { int *d; int s; public: A(int sz) : s(0) { if(s<0) throw exception(); d = new int[sz]; s = sz; // s is set at the end of the constructor } ~A() {if(s) delete[] d;} // use s as a protection }; Exception thrown in compiled code can be caught by Cint if Cint is compiled with -DG__STD_EXCEPTION. Refer to platform/README.txt for more detail. # namespace namespace is implemented with some limitation. 'namespace std' is ignored and it is merged with global scope. Using directive can not be used in global scope. Other than those, namespace works reasonably well. # dynamic_cast, static_cast, reinterpret_cast, const_cast dynamic_cast, static_cast, reinterpret_cast and const_cast are parsed by cint but behave the same as C style '(T)v' casting. dynamic_cast<T>(v) same as (T)v static_cast<T>(v) same as (T)v reinterpret_cast<T>(v) same as (T)v const_cast<T>(v) same as (T)v # RTTI RTTI library is implemented based on ANSI/ISO resolution proposal 95 spring. This specification may have been changed in final ANSI/ISO standard. # Multi-Language Cint can handle multi-byte character sets in comment and string constant. Cint attempts to judge between S-JIS and EUC automatically. This algorithm works for most cases, but not perfect. In S-JIS, half-size kana character must not be used. There may be other corner cases that the algorithm makes wrong judgment. Cint can not take JIS and Unicode. # KNOWN BUGS + static class object There is a bug in CINT interpreter declaring static class object in a function. func() { static InterpretedClass a; // FIxed in 5.13.77 static InterpretedClass b(initval); // FIxed in 5.13.77 static InterpretedClass b=initval; // CINT BUG, CAUSES ERROR static CompiledClass d; // FIxed in 5.13.77 static CompiledClass e(initval); // FIxed in 5.13.77 static CompiledClass f=initval; // FIxed in 5.13.77 static int g; // Work fine static int h(1); // Work fine static int i=1; // Work fine } # Special language extensions There are special language extension Cint allows for user's convenience. Those extensions are potentially illegal in standard C/C++. Please note that if you use Cint's unique extensions, the code will not work with C/C++ compilers. - Direct comparison of string constants char *p = "abc"; if(p=="abc") printf("true\n"); // true - Using string constant in switch statement char *p="abc"; switch(p) { case "abc": printf("match abc\n"); break; case "def": printf("match def\n"); break; default: printf("unmatch\n"); break; } - Power operator double a = 2**3; // power double b = 2@3; // power - Dynamic array allocation with non const integer as an index (This is allowed only from command interface. If this appears in a source code, cint detects it as an error.) cint> int n=5; cint> float a[n]; (This list is not complete.) # BUGS Report bugs and requirements to cint@pcroot.cern.ch. Bugs tend to be fixed very quickly. Any kind of comments or messages will be appreciated. # SEE ALSO doc/cint.txt doc/makecint.txt doc/bytecode.txt # AUTHOR Masaharu Goto (cint@pcroot.cern.ch) Copyright (c) 1995~2002 Masaharu Goto