different programming language and calling convention - c++

According to the wiki:
Different programming languages use different calling conventions, and
so can different platforms (CPU architecture + operating system). This
can sometimes cause problems when combining modules written in
multiple languages
So am I supposed to be careful when I call C/C++ functions (exported from .so/.dll) in Python?
If yes, what should I be careful of?

Calling between Python and C is a solved problem, so you generally won't have to worry about anything -- not least because Python is written in C.
The problem described there is more an issue when multiple languages on a platform are all developed independently, individually bootstrapped from assembler. For example, there used to famously be problems calling between C and FORTRAN, and between C and Pascal, at a time when all three of those languages coexisted as rough equals. The old Mac Toolbox was written mostly in assembler using Pascal calling conventions, and early application developers used Borland Pascal. But then C compilers like Symatec's THINK C appeared, and those programmers had to specifically worry about how to translate argument types and string conventions (Pascal strings carry a length byte at the beginning, and of course C strings have a 0 at the end.)

The calling convention is not an issue when calling C from python because the python interpreter itself is written in C, and thus uses the same calling convention as the C code.
It becomes an issue when combining code written in different compiled languages, for example C and Ada.
Usually C is the system programming language, and thus the standard. This means that a compiler for any language will generally have special support to inter-operate with C. See here for an example of interoperability between C and Ada. If there is no special support wrappers must be written at the assembly level.
If you need to call C++/Ada from python you'll have to follow a two steps process. The first step is to write a C wrapper around the C++/Ada functions. The second step is to call the C wrapper from python.
Take for example the following C++ class.
class Foo
{
public:
Foo ();
int bar ();
...
};
If you want to make it available to python, you first need to wrap it in C:
extern "C" {
typedef void *FooPtr;
FooPtr foo_new () { return (FooPtr)new Foo(); }
int foo_bar (FooPtr foo) { return ((Foo*)foo)->bar(); }
...
}
Then you can call that from python. (Note, in real life there are tools to automate this, like Boost.Python).
Note that there are two aspects of writing a wrapper: converting between calling conventions and converting between type representations. The later part is usually the most difficult because as soon as you go beyond basic types languages tend to have very different representations of equivalent types.

C and C++ have different calling conventions. C doesn't support calling C++ functions but C++ support calling C functions and supports the implementation of C functions in C++. That is, you can declare functions as extern "C" in C++. I don't know how the python bindings are calling C++ but you should be careful to call C and C++ functions with their respective calling conventions. Generally, C calling conventions are used when calling between different languages. This may mean that you might need to write a wrapper function using C style conventions for C++ style functions.

The calling conventions refers to how functions calls are generated in the resulting assembly. One convention is for the caller to be responsible for creating and cleaning up the stack space for the local variables. The other convention is for the called function to create and clean up the stack space for the local variables. It doesn't matter which one you use, but obviously they have to match or the stack will get corrupted.
You can see more details here: http://en.wikipedia.org/wiki/Calling_convention

Related

Why does modern C++ still retain the old C style prototype for main with int argc, char** argv

Other than backward compatibility, is there any specific reason for not changing the prototype and benefit from modern features of C++?
Modern C++ encourages the use of value semantics.
Why should argv still be a char array with pointer semantics, which could possible lead to issues if not properly handled?
In Java we have the class with, void main(String[] args).
Am I missing anything fundamental?
Other than backward compatibility
This is the reason and considered most important in moving forwards with C++.
But there is a proposal: A Modern C++ Signature for main
Many systems contain code written in languages other than C++. While it would be possible to have the main entry-point function in user code accept C++ string parameters and then have an implementation-supplied wrapper which translates the underlying platform's arguments into C++ strings and then passes them to the user-code entry point, this would only be advantageous in cases where the underlying environment represented strings in some fashion other than zero-terminated sequences of characters, and where the wrapper would be able to avoid having to first translate to C-style strings before translating into C++ strings. Otherwise, anything that could be done by the wrapper could be done just as well by user code.

Why can't C functions be name-mangled?

I had an interview recently and one question asked was what is the use of extern "C" in C++ code. I replied that it is to use C functions in C++ code as C doesn't use name-mangling. I was asked why C doesn't use name-mangling and to be honest I couldn't answer.
I understand that when the C++ compiler compiles functions, it gives a special name to the function mainly because we can have overloaded functions of the same name in C++ which must be resolved at compile time. In C, the name of the function will stay the same, or maybe with an _ before it.
My query is: what's wrong with allowing the C++ compiler to mangle C functions also? I would have assumed that it doesn't matter what names the compiler gives to them. We call functions in the same way in C and C++.
It was sort of answered above, but I'll try to put things into context.
First, C came first. As such, what C does is, sort of, the "default". It does not mangle names because it just doesn't. A function name is a function name. A global is a global, and so on.
Then C++ came along. C++ wanted to be able to use the same linker as C, and to be able to link with code written in C. But C++ could not leave the C "mangling" (or, lack there of) as is. Check out the following example:
int function(int a);
int function();
In C++, these are distinct functions, with distinct bodies. If none of them are mangled, both will be called "function" (or "_function"), and the linker will complain about the redefinition of a symbol. C++ solution was to mangle the argument types into the function name. So, one is called _function_int and the other is called _function_void (not actual mangling scheme) and the collision is avoided.
Now we're left with a problem. If int function(int a) was defined in a C module, and we're merely taking its header (i.e. declaration) in C++ code and using it, the compiler will generate an instruction to the linker to import _function_int. When the function was defined, in the C module, it was not called that. It was called _function. This will cause a linker error.
To avoid that error, during the declaration of the function, we tell the compiler it is a function designed to be linked with, or compiled by, a C compiler:
extern "C" int function(int a);
The C++ compiler now knows to import _function rather than _function_int, and all is well.
It's not that they "can't", they aren't, in general.
If you want to call a function in a C library called foo(int x, const char *y), it's no good letting your C++ compiler mangle that into foo_I_cCP() (or whatever, just made up a mangling scheme on the spot here) just because it can.
That name won't resolve, the function is in C and its name does not depend on its list of argument types. So the C++ compiler has to know this, and mark that function as being C to avoid doing the mangling.
Remember that said C function might be in a library whose source code you don't have, all you have is the pre-compiled binary and the header. So your C++ compiler can't do "it's own thing", it can't change what's in the library after all.
what's wrong with allowing the C++ compiler to mangle C functions also?
They wouldn't be C functions any more.
A function is not just a signature and a definition; how a function works is largely determined by factors like the calling convention. The "Application Binary Interface" specified for use on your platform describes how systems talk to each other. The C++ ABI in use by your system specifies a name mangling scheme, so that programs on that system know how to invoke functions in libraries and so forth. (Read the C++ Itanium ABI for a great example. You'll very quickly see why it's necessary.)
The same applies for the C ABI on your system. Some C ABIs do actually have a name mangling scheme (e.g. Visual Studio), so this is less about "turning off name mangling" and more about switching from the C++ ABI to the C ABI, for certain functions. We mark C functions as being C functions, to which the C ABI (rather than the C++ ABI) is pertinent. The declaration must match the definition (be it in the same project or in some third-party library), otherwise the declaration is pointless. Without that, your system simply won't know how to locate/invoke those functions.
As for why platforms don't define C and C++ ABIs to be the same and get rid of this "problem", that's partially historical — the original C ABIs weren't sufficient for C++, which has namespaces, classes and operator overloading, all of which need to somehow be represented in a symbol's name in a computer-friendly manner — but one might also argue that making C programs now abide by the C++ is unfair on the C community, which would have to put up with a massively more complicated ABI just for the sake of some other people who want interoperability.
MSVC in fact does mangle C names, although in a simple fashion. It sometimes appends #4 or another small number. This relates to calling conventions and the need for stack cleanup.
So the premise is just flawed.
It's very common to have programs which are partially written in C and partially written in some other language (often assembly language, but sometimes Pascal, FORTRAN, or something else). It's also common to have programs contain different components written by different people who may not have the source code for everything.
On most platforms, there is a specification--often called an ABI [Application Binary Interface] which describes what a compiler must do to produce a function with a particular name which accepts arguments of some particular types and returns a value of some particular type. In some cases, an ABI may define more than one "calling convention"; compilers for such systems often provide a means of indicating which calling convention should be used for a particular function. For example, on the Macintosh, most Toolbox routines use the Pascal calling convention, so the prototype for something like "LineTo" would be something like:
/* Note that there are no underscores before the "pascal" keyword because
the Toolbox was written in the early 1980s, before the Standard and its
underscore convention were published */
pascal void LineTo(short x, short y);
If all of the code in a project was compiled using the same compiler, it
wouldn't matter what name the compiler exported for each function, but in
many situations it will be necessary for C code to call functions that were
compiled using other tools and cannot be recompiled with the present compiler
[and may very well not even be in C]. Being able to define the linker name
is thus critical to the use of such functions.
I'll add one other answer, to address some of the tangential discussions that took place.
The C ABI (application binary interface) originally called for passing arguments on the stack in reverse order (i.e. - pushed from right to left), where the caller also frees the stack storage. Modern ABI actually uses registers for passing arguments, but many of the mangling considerations go back to that original stack argument passing.
The original Pascal ABI, in contrast, pushed the arguments from left to right, and the callee had to pop the arguments. The original C ABI is superior to the original Pascal ABI in two important points. The argument push order means that the stack offset of the first argument is always known, allowing functions that have an unknown number of arguments, where the early arguments control how many other arguments there are (ala printf).
The second way in which the C ABI is superior is the behavior in case the caller and callee do not agree on how many arguments there are. In the C case, so long as you don't actually access arguments past the last one, nothing bad happens. In Pascal, the wrong number of arguments is popped from the stack, and the entire stack is corrupted.
The original Windows 3.1 ABI was based on Pascal. As such, it used the Pascal ABI (arguments in left to right order, callee pops). Since any mismatch in argument number might lead to stack corruption, a mangling scheme was formed. Each function name was mangled with a number indicating the size, in bytes, of its arguments. So, on 16 bit machine, the following function (C syntax):
int function(int a)
Was mangled to function#2, because int is two bytes wide. This was done so that if the declaration and definition mismatch, the linker will fail to find the function rather than corrupt the stack at run time. Conversely, if the program links, then you can be sure the correct number of bytes is popped from the stack at the end of the call.
32 bit Windows and onward use the stdcall ABI instead. It is similar to the Pascal ABI, except push order is like in C, from right to left. Like the Pascal ABI, the name mangling mangles the arguments byte size into the function name to avoid stack corruption.
Unlike claims made elsewhere here, the C ABI does not mangle the function names, even on Visual Studio. Conversely, mangling functions decorated with the stdcall ABI specification isn't unique to VS. GCC also supports this ABI, even when compiling for Linux. This is used extensively by Wine, that uses it's own loader to allow run time linking of Linux compiled binaries to Windows compiled DLLs.
C++ compilers use name mangling in order to allow for unique symbol names for overloaded functions whose signature would otherwise be the same. It basically encodes the types of arguments as well, which allows for polymorphism on a function-based level.
C does not require this since it does not allow for the overloading of functions.
Note that name mangling is one (but certainly not the only!) reason that one cannot rely on a 'C++ ABI'.
C++ wants to be able to interop with C code that links against it, or that it links against.
C expects non-name-mangled function names.
If C++ mangled it, it would not find the exported non-mangled functions from C, or C would not find the functions C++ exported. The C linker must get the name it itself expects, because it does not know it is coming from or going to C++.
Mangling the names of C functions and variables would allow their types to be checked at link time. Currently, all (?) C implementations allow you to define a variable in one file and call it as a function in another. Or you can declare a function with a wrong signature (e.g. void fopen(double) and then call it.
I proposed a scheme for the type-safe linkage of C variables and functions through the use of mangling back in 1991. The scheme was never adopted, because, as other have noted here, this would destroy backward compatibility.

calling c code from c++

how does a call from c++ to c work internally??
The C++ compiler 'does the right thing' and uses the correct calling convention for the C function - a lame sounding answer but I don't know that there's much more that can be said!
It is a heavy duty implementation detail. But most C++ compilers I know don't try to do anything special to differentiate a C function from a non-instance C++ function. Just the plain olden cdecl calling convention for both.
Kinda important because the CRT implementation, with functions like printf(), are just as usable by a C compiler as they are by the C++ compiler from the same vendor. Nobody wants to maintain two versions of it.

Using Fortran to call C++ Functions

I'm trying to get some FORTRAN code to call a couple c++ functions that I wrote (c_tabs_ being one of them). Linking and everything works just fine, as long as I'm calling functions that don't belong to a class.
My problem is that the functions I want the FORTRAN code to call belong to a class. I looked at the symbol table using nm and the function name is something ugly like this:
00000000 T _ZN9Interface7c_tabs_Ev
FORTRAN won't allow me to call a function by that name, because of the underscore at the beginning, so I'm at a loss.
The symbol for c_tabs when it's not in a class is quite simple, and FORTRAN has no problems with it:
00000030 T c_tabs_
Any suggestions? Thanks in advance.
The name has been mangled, which is what the C++ compiler does to functions to allow things like function overloading and type-safe linkage. Frankly, you are extremely unlikely to be able to call member functions from FORTRAN (because FORTRAN cannot create C++ class instances, among other reasons) - you should express your interface in terms of a C API, which will be callable from just about anywhere.
You will need to create a c-style interface and "extern" it. C++ mangles method names (and overloaded functions) for linking. It's notoriously difficult to link C++ with anything except C++. There are "ways" but I'd highly suggest that you simply export a C interface and use the standard facilities available in Fortran.
If you make the C++ routine have a C-style interface (as described already), then you can use the ISO C Binding feature of Fortran 2003 to call it. With the ISO C Binding, you can specify the name of the routine and (within limits) the C-types and calling conventions (reference, by value) of the arguments and function return. This method works well and has the advantage of being a standard, and therefore compiler and platform dependent, unlike the old methods of calling C from Fortran. The ISO C Binding is supported by many Fortran 95 compilers, such as gfortran >= 4.3.
You have to create extern "C" wrappers to handle all the details of FORTRAN calling C++, name mangling being the most obvious.
class foo {
public:
int a_method (int x);
}
extern "C" int foo_a (foo * pfoo, int * px) {
if (NULL == pfoo)
return 0;
else
return pfoo->a_method (*px);
}
Notice that FORTRAN compilers pass all arguments by reference, never by value. (Although I'm told this is not strictly speaking part of the FORTRAN standard.)

Is there something that I can do in C but I can't do in C++? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
Is there something that I can do in C but I can't do in C++ ?
I stumbled upon the question in a sample interview questions site.
Declare a variable named 'class', as in:
int class = 0;
...that is there anything I can do in C but not in C++.
Both languages are Turing complete, so in theory you can code up equally functional applications in both.
OTOH, C++ is not a superset of C. Especially C99 has some features that C++ does not have. E.g. designated initializers, variable length arrays in structs and as automatic variables. Depending on your "anything", this could be something that C++ cannot do but C can.
In C, you can create array literals ("compound literal"), but in C++ you cannot
/* p points to the first element of an array of 4 int */
int *p = (int[]){1, 2, 3, 4};
You can also create an array with size not yet known at compile time, but C++ has no such possibility ("variable length array"):
// create array. size is known at runtime only.
int p[rand() % 5 + 1];
int new = 0;
works in C, but obviously can't work in C++ because 'new' is a reserved word.
There are some other 'tricks' with reserved words, but other than that, you can pretty much do everything in C that you can do in C++.
Quite a few things. For example, in C you can write code like this:
void * v = 0;
char * p = v;
and you can create arrays like this:
int main() {
int n = 42;
int a[n];
return 0;
}
neither of which will compile under C++.
C++ lacks C99's restrict qualifier. Therefore, there is no way to tell the compiler to perform optimizations based around knowing that pointers aren't aliases.
There are some things you can say in C wihch you can't in C++ (because C++ has stricter syntax-checking, and C has a more extensive 'legacy' syntax).
Also, there may be some run-time environments (O/S+library+compiler) which support C but not C++, so you can do C on those platforms where you can't do C++.
Syntactically there are a few things you could write in C that wouldn't compile in C++ (See Incompatibilities Between ISO C and ISO C++ for excruciating details.). If you're asking at a higher level, if there is some program that it's possible to write in C, but not possible to write in C++, then the answer is "No."
Actually, I can think of one example:
When you create a library (.lib file or .dll file) to be shared by other applications, you're better off using C instead of C++ because the results are more portable. You can do this within a C++ compiler by using an 'extern "C"' block though.
Specifically, C++ has a quirk where there is no standard convention for name mangling - for translating your library's function signatures into more low level names used by the compiler. So for example if you have a function like 'int addNumbers (int a, int b)', different C++ compilers may translate this function into different names, which can lead to problems when you want to import the library. If you use a C compiler or surround your library importing and exporting code with a C block though you won't see this problem, since there is only one way to mangle function names in C.
In 'C' you don't need forward declarations. This allows you to pass parameters which are interpreted incorrectly. (Not that this is a great feature, but you can't do it in C++)
in file A:
float sum(float a, float b)
{
return a+b;
}
in file B
main()
{
printf("%f\n", sum(1,2));
}
with C, this compiles, but prints 0.000
with C++, you need a float sum(float,float); before the printf, and it gives the expected result.
You can sparsely initialize arrays in C. I like to use it for mapping int->sometype for relatively dense static maps where an unmapped value can be interpreted as 0:
int my_array[] = { [1] = 3, [4] = 2 };
printf("%d %d %d\n", sizeof my_array, my_array[0], my_array[1]);
/* prints 20, 0, 3 */
The 1998 C++ standard has a list of incompatibilities with the 1990 C standard that is 13 pages long (Annex C). Granted, it's not a lot, compared to the amount of pages that describe the languages, but still covers quit a bit of ground.
Quick summary of the kind of differences that it lists:
New keywords are added (any C program that uses them as identifiers is not C++)
Type of character literal changed from int to char (compare sizeof('a') in C and C++!)
String literals made const (can't do char* q = expr ? "abc" : "de";)
"Tentative definitions" are removed from the language.
"Compatible types" are removed from the language.
Converting from void* to any other pointer now requires casting.
Converting from any const/volatile pointer to void* now requires casting.
"Implicit declarations" are removed from the language.
Expressions can no longer create new types (as in p = (void*)(struct x {int i;} *)0; )
results of some expressions became lvalues (compare sizeof(0, arr) for char arr[100];)
...that was the first 3 pages of Annex C.
If you go to the 1999 C standard, the differences are going to take forever to describe. Although C++0x did include some of C99 features, many of them are just inherently incompatible, like the complex type.
In C, you can declare variables with the following names:
bool, class, new, delete, template, typename, this, throw, catch,
typeid, operator, virtual, static_cast, reinterpret_cast,
dynamic_cast, mutable, public, private, protected, friend; //many more
then you can do these:
int namespace = private + protected + public;
int decltype = static_cast + dynamic_cast + reinterpret_cast;
int constexpr = (new + delete) * (template + typename);
All of them are keywords in C++11.
You can do almost everything in any of the programming languages. Of course the way of expressing it will vary, as well as the amount of code, clarity of code, ease of further maintenance. Some tasks can be coded with few lines in Prolog and few pages of code in C++, and so on.
Some limiting factors are the available libraries, available compilers, and low-level issues. However when you consider C and C++ on a typical PC, then there is no difference in things that can be done in either of them.
Unless of course you were asking for the differences between C and C++ - for these other people have given you the idea.
char *c = malloc(sizeof(char));
is valid in C, not C++ i.e. automatically casting void*. This of course is a syntax issue, not so much as what you can and cannot _do_ (i.e. accomplish).
If the criteria is to solve a particular programming problem then both will do the job although it may be a bit easier in some cases to do it in C++ due to the higher level of abstraction
Is this referring to the latest C standard? The original C standard (ANSI 1989 or ISO 1990, with 1995 updates) is fairly close to being a subset of C++. There's differences, but they're mostly contrived (the biggest exception probably being that void * converts freely with any data pointer in C but not in C++).
However, a new C standard came out in 1999, some time after I'd stopped doing anything in the most modern C. It had new features, some of which are going into the C++ standard due this year or next, but not all.
C++ is obviously not a superset of C for a very simple reason: New keywords have been added to C++
class, virtual, new, etc and thus can no more be used as identifiers in C++.
Some of the reasons are subtler.
You can find an exhaustive answer to this question on Bjarn Stroustrup's website:
The C++ programming language | Appendix B
C can have a function with an unspecified amount of arguments. Disclaimer that this is bad practice and shouldn't be used, but present and interesting nonetheless:
void x() { }
in C means a function with an unspecified amount of parameters. This is as opposed to
void x(void) { }
Which means a function with 0 parameters in C. In C++ both functions mean the same thing and take 0 arguments.
Using the unspecified parameter count in C, you could access the parameters the same way you would using variable arguments.
So:
void x()
{
}
int main()
{
// This line would compile in C and C++
x();
// This line compiles in C but not C++
x(5, 7)
return 0;
}
That is why you should try to write void as a parameter instead of leaving them blank. In C always explicitly write void so you don't have issues, and inC++ both are equivalent so it doesn't matter but it's nice to be explicit.
Many aspects of hardware-related embedded ("freestanding") systems programming are only possible in C.
[Major difference] In C you can do union type punning, which is done is pretty much every professional microcontroller hardware peripheral register map ever written. This is undefined behavior in C++.
In C you can use the de facto standard freestanding implementation-defined form of main() as void main (void). This is not allowed in C++ because of artificial restrictions. You must either have your bare metal C++ program return a value to la-la-land or name the procedure entered at startup something else than main.
When using structs allocated with static storage duration in C, you can have them quickly initialized with just a "zero out" (.bss initialization). Doing the same in C++ with structs/classes will mean that member variables get "zeroed out" too, but in addition default constructors will get called, leading to needlessly slow program startup.
[Major difference] In C you can declare const variables without initializing them. This is very useful for const volatile variables declared in EEPROM/flash, to be written to in run-time by bootloaders and similar. In C++ you are forced to initialize the variables, which in turn forces default values to get burned into EEPROM/flash, leading to slower programming time and slightly more physical memory wear.
[Major difference] No standard library function in C performs heap allocation silently/implicitly, apart from the malloc family (and in C23, strdup as well). In C++, silent heap allocation is very common in standard library functions, making those libraries unsuitable for embedded systems.
restrict pointers are possible to use in C for various micro-optimizations.
C allows pointers to VLA, which can help improving readability and diagnostics. On the other hand, C++ doesn't allow objects of VLA type, which is a good thing in embedded systems. C compilers can optionally refuse to implement certain aspects of VLA depending on their standard compliance (C99 vs C11/C17 vs C23 - C23 being the most suitable for embedded systems in regards of VLA).
C++ didn't support designated initializers until C++20 and these are quite handy to have in all manner of situations. (C++ does support initializer lists with named members inside constructors, however.)
C doesn't allow exception handling and I'd say that's a huge benefit in embedded systems. You'll want to avoid opening that can of worms inside your deterministic firmware. Error handling in C is rather handled gracefully by returning an error code from one module to its caller and then further down the line as needed. Instead of violently crashing down the dependency chain if left unhandled, just like the average run-away code bug would. It is however possible to write exception-free code in C++ too, if done with great care.
(Major) "Forever loops" is an important concept in programming, particularly so in embedded systems programming, where even empty loops with no side effects are common. And yet C++ doesn't support that. Optimizing away a "while(1);" in C++0x. A perfectly valid embedded systems program might look like init_interrupts(); for(;;){}. However, the C++ committee have apparently not taken such very common scenarios in consideration, so you can't write such programs in C++.
Benefits of C++ over C in hardware-related programming:
Inline assembler is standardized in C++, since C++ predicted that the programs written in it would get executed on computers. C did make no such prediction and so inline assembler/running your C program on a computer is not yet supported even in C23. It's just sad. (Similarly sad, neither language has a standardized interrupt keyword.)
C++ historically has a much better system for static assertions than C, which didn't support them proper until C11 (and further support is added in C23).
C++ guarantees a diagnostic message when doing implicit pointer conversions to/from void*. C does not. And void pointers are generally to be avoided in embedded systems.
You cannot call main() recursively in C++.
Conditional expressions with logic/relational/equality operators in C++ result in bool.
Character constants ('A') are of type char in C++, which saves a tiny bit of memory.
"If it can't be done in assembly, it's not worth doing!"
ok, humor aside, I THINK the OP is asking syntactically, rather than operationally.
I think that there are a few obscure things that are legal in C (at least C89) that are not legal in C++, or at least deprecated... But (if they exist) they're pretty obscure. C++ is functionally a superset of C.
C++ does not support named struct member initialization but in C you can do:
struct { int x, y; } a = { .x = 3 };
You can also combine this with the feature shown by Matt Havener:
struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2 };
The short answer is...no, not really. See http://www.research.att.com/~bs/bs_faq.html#difference