C++ 中static extern "C" 函数
时间:2010-07-16 来源:slimzhao
extern 单独使用用于修饰函数时表示显式声明可见性是跨编译单元的, 也就意味着这个符号被写在.obj文件中, 在链接阶段对其它的目标文件是可见的. 在文件范围内声明函数时, extern的使用是冗余的, 函数声明如果没有指定static, 其可见性默认就是extern的.
表面上, 这两个关键字是互斥的, 但extern "C" 合起来使用, 却对编译器有不同的语意. 下面看到的一篇文章很好的解释了这一点:
http://everything2.com/title/C%252B%252B%253A+static+extern+%2522C%2522
No, really. C++ not only lets you declare a ``static extern "C"'' function, it even requires you to do so in some circumstances. This is another tale of woe from the battles of hapless programmers to write compliant code and stay a part of the C++ programming language freakshow.
C++ is just like C. And in C, ``static'' is the antonym of ``extern'', at least as far as function declarations go. Saying
static extern int f(int);in C pretty much guarantees the compiler will question your obviously lacking intelligence and print some insulting message. So why would a C++ programmer want to say this? I thought C++ is a superset of C! Aren't C++ programmers supposed to be smarter than C programmers, anyway?Actually, the compiler requires it in certain circumstances. Suppose you have some function written in C, which takes a callback argument. For concreteness, I'll talk about qsort. STL has its own sort, so this situation might still appear a bit far-fetched. But not every project can use STL. And when your project has a mature, working, debugged C library, you use it, even from C++.
You tell your C++ compiler about this function:
extern "C" qsort(void *base, size_t nmemb, size_t size,qsort is a C function, taking the described arguments.
int (*compar)(const void *, const void *));
Now you want to write a comparison function for pointers to members of some POD class A. It's just a static function -- you only need it in the one source file (sorry, translation unit) where you call the C function:
static int cmp_A(const void* a, int void* b)And you want to pass the function pointer cmp_A to qsort -- after all, it has the right type, doesn't it?
{
const A* aa = const_cast<const A*>(a);
const B* bb = const_cast<const A*>(b);
return aa > bb ? -1 : bb < aa ? +1 : 0;
}
Errm, no, it doesn't. Sun Workshop's CC warns of "anachronism", and asks that you declare cmp_A as extern "C". Why?
Well, it's not the name mangling issue, or anything to do with external linkage. After all, cmp_A is invisible outside this source file (sorry, translation unit) -- it's static!
But ``recall'' from extern "C" that this declaration affects not just linkage, but also calling convention (ABI). Not that any C++ compiler on the face of this God-forsaken planet actually uses a different calling convention for its functions than the platform's ABI guarantees for C. But it might. In effect, C++ regards the extern "C" declaration as also affecting any function pointers taken by that function!
Now, the function qsort is already written. In C. And it expects a function pointer to a function with C calling convention. So to pass it a function from C++, that function must have the C calling convention -- extern "C". And since we don't want it visible outside its source file (translation unit, sorry), it must also be static. So we declare cmp_A to be ``static extern "C"''. And another syntacticmonstrosity is born.
premchai21 notes (correctly, of course!) that modern ISO C++ deprecates this use of "static", preferring instead the use of an unnamed namespace. The true modern style would instead use
namespace {to declare and define cmp_A.
extern "C" int cmp_A(const void* a, int void* b)
{
const A* aa = const_cast<const A*>(a);
const B* bb = const_cast<const A*>(b);
return aa > bb ? -1 : bb < aa ? +1 : 0;
}
}
Note the pretty "extern" in there. It's still not an external function -- the nameless namespace ensures it's invisible outside the filetranslation unit.