本页面旨在记录为C库创建FB绑定时常遇到的问题和解决方案。
一般来说,FB和C / C ++非常相似。FB在适用的情况下遵循与GCC相同的ABI,以尽可能地兼容二进制。语言语法也类似于C / C ++。因此,很多类型和过程声明可以在C和FB之间直接转换1:1。然而,还有一些不能直接翻译的结构,例如:typedefs声明函数类型。FB具有函数指针类型,但不是简单的函数类型。
- 好消息:我们有工具(fbfrog和h_2_bi),可以自动进行大部分翻译。
- 坏消息:总有一些问题不能自动解决,因此需要手动修复。
数据类型
C / C ++类型 | 大小(字节数)(Linux / Windows上的GCC) | 相应的FreeBASIC类型 |
烧焦 | 1 | 字节 |
短[int] | 2 | 短 |
INT | 4 | 长 |
枚举(底层类型int) | 4 | 长 |
长长[int] | 8 | LongInt |
浮动 | 4 | 单 |
双 | 8 | 双 |
长双 | 12是32位,64位16 | 来自crt / longdouble.bi的CLongDouble |
_Bool /布尔en | 1 | 字节 |
*(指针) | 图4是一个32位,64位8 | Ptr/Pointer |
ssize_t,intptr_t | 图4是一个32位,64位8 | 整数 |
size_t,uintptr_t | 图4是一个32位,64位8 | UInteger |
长[int] | 4位32位系统和Win64(!),8位64位Linux / BSD | 来自crt / long.bi |
- 警告:int/ long不是Integer/ Long.在FB中,Integer对应于Pointer - 它是32位32位,64位64位(在所有操作系统上)。Long到处都是32位。在C中,int保持32位,long仅对应于Linux / BSD系统上的指针,但不对应于Win64,其中long仍为32位。在Win64上,long long是C中唯一的64位整数类型。因此,C的int和C的long都不兼容FB的Integer.
- 警告:long int不是LongInt.FB的LongInt对应于C的long long,而不是C的long.
- int可以翻译成Long,因为两者都是32位。
- ssize_t或intptr_t可以转换为Integer,因为它们的大小通常与指针相同。
- long不能直接翻译,但我们提供了clong和culong类别别名的crt/long.bi.
- long double不能直接翻译,但我们提供了clongdouble类型的目标特定clongdouble.
- enum??是一个特例。通常它们的底层类型是int(32bit),但在FB Enum中使用Integer(32bit / 64bit),并且不允许改变它。因此,enums(用作声明中的数据类型)不能翻译为Enums.
例如:
必须翻译为:
Type MyEnum As Long
Enum
A
B
End Enum
- BOOLBOOL只是int的typedef,不应与C _Bool或C ++ bool类型混淆。
符号名称冲突
- C / C ++区分大小写,约50个关键字
- FreeBASIC不区分大小写,约400个关键字
- C代码有时使用FB关键字作为符号标识符,例如INT,string,open.这些符号必须重命名。
- C代码通常包含仅在情况下不同的标识符,例如GET_VERSION和get_version.这是FB不允许的其中一个符号必须重命名。
- 在C中,宏可以具有与功能相同的标识符。这是FB不允许的其中一个符号必须重命名。
例子
使用FB关键字作为标识符的C代码:
typedef Int Int;
void Open(void);
Type INT_ As Long
Declare Sub open_ cdecl Alias "open"()
C代码依赖于区分大小写:
void foo(void);
void Foo(void);
void FOO(void);
'' Wrong translation:
Extern "C"
Declare Sub foo()
Declare Sub Foo() '' error: duplicate definition
Declare Sub FOO() '' error: duplicate definition
End Extern
'' Correct translation:
Extern "C"
Declare Sub foo()
Declare Sub Foo_ Alias "Foo"()
Declare Sub FOO__ Alias "FOO"()
End Extern
发生这种冲突的另一个典型例子是:
#define GET_VERSION_NUMBER 123
Int get_version_number(void);
Extern "C"
#define GET_VERSION_NUMBER_ 123 '' renamed to avoid conflict
Declare Function get_version_number() As Long
End Extern
程序与宏之间的冲突:
void f(Int);
#define f(i) f(i + 1)
Extern "C"
Declare Sub f(ByVal As Long)
#define f_(i) f(i + 1) '' renamed to avoid conflict
End Extern
解决方案
- 应通过附加_下划线重新命名符号。这样我们解决冲突,仍然保持接近原始的API。
- 重命名符号不应该导致进一步的重命名(例如,如果foo必须重命名,但foo_已经存在,则foo应该重命名为foo__)
- 重新命名的符号列表应该在绑定或绑定文档中可用,以便用户可以将原始API识别出这些差异。
- 结构中的字段不需要重命名,只因为它们匹配FB关键字。通过使用“As DataType Name”语法,可以使用FB关键字作为标识符。只要它是一个简单的结构(简单的旧数据),而不是一个类,这只能起作用。
Type UdtWithKeywordFields
As ZString Ptr String '' Field "String" of type ZString Ptr
As Long Type '' Field "Type" of type "Long"
As Long As '' Field "As" of type "Long"
End Type
功能类型
在C中,可以使用具有函数类型的typedef。取消引用函数指针类型会导致函数类型。FB只有函数指针类型,而不是函数类型。
// A Function typedef (Function result = void, no parameters)
typedef void F(void);
// Using it To Declare a Function called f1
F f1;
// Usually f1 would be declared like This (use of Function typedefs Is pretty rare):
void f1(void);
// A more Common use For Function typedefs Is To Declare pointers To them (Function pointers):
Extern F *pf1;
由于FB没有函数类型,所以这些typedef必须被解析出来,或者变成一个函数指针:
Extern "C"
Type F As Sub() '' Function pointer type
'' Declaring procedures is only possible with Declare in FB
Declare Sub f1()
'' But at least FB has function pointer types.
'' Since F already is the function pointer in the FB translation, there is no extra PTR here
Extern pf1 As F
End Extern