Swift 项目中的 C 代码
Posted
技术标签:
【中文标题】Swift 项目中的 C 代码【英文标题】:C code in Swift Project 【发布时间】:2015-12-12 14:35:26 【问题描述】:我有一个 C 程序,我想从 swift 打印它的输出,当它扫描时,我可以通过 Swift 给它输入。这样的事情可能吗?我用一个简单的函数尝试了这个,它成功了,但是有人怎么能用许多不同的函数来调用其他函数呢?
我知道这个问题有点含糊,但有人能指出我正确的方向吗?
代码示例:
int main(int argc, char **argv)
int i;
int hitme;
char ch;
prelim();
if (argc > 1) // look for -f option
if (strcmp(argv[1], "-f")== 0)
coordfixed = 1;
argc--;
argv++;
if (argc > 1)
fromcommandline = 1;
line[0] = '\0';
while (--argc > 0)
strcat(line, *(++argv));
strcat(line, " ");
else fromcommandline = 0;
while (TRUE) /* Play a game */
setup();
if (alldone)
score(0);
alldone = 0;
else makemoves();
skip(2);
stars();
skip(1);
if (tourn && alldone)
printf("Do you want your score recorded?");
if (ja())
chew2();
freeze(FALSE);
printf("Do you want to play again?");
if (!ja()) break;
skip(1);
prout("May the Great Bird of the Galaxy roost upon your home planet.");
return 0;
【问题讨论】:
【参考方案1】:是的。
Using Swift with Cocoa and Objective-C 对此进行了广泛的介绍。 Objective-C 是 C 的超集,因此 Objective-C 的所有指令都同样适用于 C。
简而言之,您只需将 C 代码添加到项目中,将其标头导入您的 Objective-C Bridging Header 中,然后 C 函数将在 Swift 中可用(使用各种自动翻译)。
也就是说,如果您真的想读取输出(即这些 printf
调用的结果),那就有点不同了。如果可以的话,我会避免它。否则,您需要将 C 程序构建为自己的可执行文件,并在 Swift 中使用 NSTask
调用它并捕获输出,或者您必须使用 fdopen
之类的东西劫持标准输出。完全正确地做到这一点很痛苦。
【讨论】:
fwopen(3)
让 C 代码直接调用 OP 的函数也是一种选择。
@rob 好吧,基本上我正在用 C 语言创建一个旧的命令行游戏。我希望游戏玩法保持不变,而是通过文本字段进行输入。所以你的意思是,我可以将代码编译为可执行文件,并将参数传递给它,并将其显示在滚动视图上,从技术上讲这是可能的吗?顺便说一句,这是针对 ios 的。但是这个方法在应用商店是不允许的,对吧?
正确。您不能在带有 iOS 的 App Store 上使用 NSTask。不过@a3f 的fwopen
建议还是不错的。
@a3f 任何关于我应该从哪里开始的指南、教程或类似的东西,我找不到任何东西!
@AhmedNassar 我写了一个答案,我在其中详细说明了一点。但一般来说,手册页始终是一个不错的起点。【参考方案2】:
我将专注于您问题的第二部分,如何与使用标准 IO 设施的 C 代码进行交互:
正如 Rob Napier 所指出的,显而易见的选择是将 C 代码编译成可执行文件,并使用类似于 popen(3)
的东西来读取和写入其标准 IO 设施,就像读取/写入任何其他 @987654322 一样@。
另一种方法是寻找使用 stdio 的地方并更改这些功能。例如,您可以使用
#ifdef STANDALONE
#define print printf
#else
#define print passToSwift
#endif
然后您可以将所有printf
s 更改为print
s 和#define
您希望您的C 代码在哪种模式下运行。如果STANDALONE
未定义,您必须提供@ 987654328@ 函数将连接您的 C 和 Swift 功能。
另一种无需更改所有printf
s 的方法是使用funopen(3)
或朋友,尤其是fwopen(3)
。使用fwopen(3)
(man fwopen
),您可以提供passToSwift
函数,以便在向stdout
写入内容时调用。
#include <stdio.h>
int passToSwift(void * cookie, const char * buffer, int len)
(void)cookie;
// do stuff with the buffer you recieved
return len;
int main(void)
fflush(stdout);
stdout = fwopen(NULL, passToSwift);
printf("Hey\n");
stdout
的分配不可移植,但在 OS X 上对我有用。我不知道有任何其他方法可以实现它。 (dup2
为funopen
d 个流提供EBADF
,freopen
期望在文件系统中有一个条目。
【讨论】:
一般来说,你应该把你的“业务”和你的 IO 东西分开。如果你这样做了,你只需要提供新的 IO 功能,甚至不需要触及游戏逻辑。 如何将缓冲区 passToSwift 存储到 swift 中的变量?【参考方案3】:我正在解决一个非常相似的问题。 我有一个可以讨论 codereview 的解决方案:C hack: replace printf to collect output and return complete string by using a line buffer 也许您也可以将它(或其中的一部分)用于您的文字游戏......
【讨论】:
【参考方案4】:C hack: replace printf to collect output and return complete string by using a line buffer 的改进版本现在作为 Xcode 7 项目 swift-C-string-passing(和 standalone gcc version)在 github 上可用。
特别是查看 #define
预处理器语句以利用桥接 swift(类似于 a3f 的答案)。
我的解决方案能够将字符串传入和传出 C 代码。但是如何从用户那里检索到答案? IE。 ja()
函数有什么作用?
【讨论】:
以上是关于Swift 项目中的 C 代码的主要内容,如果未能解决你的问题,请参考以下文章
我如何从目标 c 代码中获取 Swift AppDelegate 的参考
通过在 iOS 中创建桥文件在 Objective-C 项目中使用 Swift 代码
构建时的 Segfault 代码 11 可能是由 Swift 项目中的 Objective-C Singleton 引起的