C hack:使用行缓冲区替换printf以收集输出并返回完整的字符串

C hack:使用行缓冲区替换printf以收集输出并返回完整的字符串,c,string,swift,char,stdout,C,String,Swift,Char,Stdout,我想把这个很棒的C程序嵌入到iOs应用程序中。 其中一个将命令行参数传递给它,结果通过printf和fputs打印到stdout,就像所有好的旧unix程序一样 现在我只想编辑main和print函数,以使用我自己的printf函数,它收集所有通常发送到stdout的输出,并在最后返回 我实现了一个解决方案,使用一个行缓冲区收集所有printf,直到换行。 以及一个动态字符数组,当输出行完成时,我将复制该数组 这个解决方案的魅力在于——它有点像tcl:只需将所有内容都放到一个文本行中,如果它完整

我想把这个很棒的C程序嵌入到iOs应用程序中。 其中一个将命令行参数传递给它,结果通过printf和fputs打印到stdout,就像所有好的旧unix程序一样

现在我只想编辑main和print函数,以使用我自己的printf函数,它收集所有通常发送到stdout的输出,并在最后返回

我实现了一个解决方案,使用一个行缓冲区收集所有printf,直到换行。 以及一个动态字符数组,当输出行完成时,我将复制该数组

这个解决方案的魅力在于——它有点像tcl:只需将所有内容都放到一个文本行中,如果它完整的话,就可以存储它。现在,只要有必要,就这么做,并在结束时返回整批

这里是一个问题: 它是有效的——但由于我对“真实”编程相当陌生——例如C和苹果的“brandnew”Swift——我不确定这是否是一个好的解决方案。它是?如果不是,你有什么建议?多谢各位

下面是C代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

// outLineBuffer collects one output line by several calls to tprntf
#define initialSizeOfReturnBuffer 10 // reduced for testing (would be 16*1024)
#define incrSizeOfReturnBuffer 5     // reduced for testing (would be 1024*1024)
#define outLineBufferMaxSize 4095
char outLineBuffer[sizeof(char)*outLineBufferMaxSize] = "";
char *tReturnString;
size_t sizeOfReturnBuffer, curPosOutBuffer = 0, lenOutLine = 0;
以及当我们完成一个输出行时的函数(无论打印到何处):


我确信tcl有很多优化,我建议您也优化代码;那么你的方法是可行的

检查您是否经常使用
strlen
,每次都会使用所有(许多)字符来计算长度-使用有关其长度的信息,例如维护
char*outlinebufftr
。也可以使用
strcat
将\n附加到
outLineBuffer
中,而不是使用昂贵的
vsnprintf
功能,或者只是手动复制字符,如
*outLineBuffer++='\n'


要实现像您这样的高级概念,您必须开始在机器循环中思考,这样高级概念就不会变得“昂贵”。

如果程序可以运行,但您想做得更好,您应该在上发布好的,谢谢!将其移至“我正在投票”以关闭此问题,因为没有代码审查网站。通过更好的
strlen
调用提高性能-如果您对最终版本感兴趣,请参阅。现在github上甚至有一个完整的Xcode项目。。。谢谢你的想法!
// replace printf with this to collect the parts of one output line.
static int tprntf(const char *format, ...)
{
    const size_t maxLen = sizeof(char)*outLineBufferMaxSize;
    va_list arg;
    int done;

    va_start (arg, format);
    done = vsnprintf (&outLineBuffer[lenOutLine], maxLen-lenOutLine, format, arg);
    va_end (arg);
    lenOutLine = strlen(outLineBuffer);

    return done;
}
// Output line is now complete: copy to return buffer and reset line buffer.
static void tprntNewLine()
{
    size_t newSize;
    long remainingLenOutBuffer;
    char *newOutBuffer;

    remainingLenOutBuffer = sizeOfReturnBuffer-curPosOutBuffer-1;
    lenOutLine = strlen(outLineBuffer)+1; // + newline character (\n)
    remainingLenOutBuffer -= lenOutLine;

    if (remainingLenOutBuffer < 0) {
        newSize = sizeOfReturnBuffer + sizeof(char)*incrSizeOfReturnBuffer;
        if ((newOutBuffer = realloc(tReturnString, newSize)) != 0) {
            tReturnString = newOutBuffer;
            sizeOfReturnBuffer = newSize;
        } else {
            lenOutLine += remainingLenOutBuffer; //just write part that is still available
            remainingLenOutBuffer = 0;
        }
    }

    snprintf(&tReturnString[curPosOutBuffer], lenOutLine+1, "%s\n", outLineBuffer);

    curPosOutBuffer += lenOutLine;
    outLineBuffer[0] = 0;
    lenOutLine = 0;
}
int main(int argc, char *argv[])
{
    int i;
    sizeOfReturnBuffer = initialSizeOfReturnBuffer*sizeof(char);
    if ((tReturnString = malloc(sizeOfReturnBuffer)) == 0) {
        return 1; // "Sorry we are out of memory. Please close other apps and try again!";
    }
    tReturnString[0] = 0;

    for (i = 1; i < argc; i++) {
        tprntf("%s ", argv[i]);
    }
    tprntNewLine();

    tprntf("%s", "ABC\t");
    tprntf("%d", 12);
    tprntNewLine(); // enough space for that ;-)
    tprntf("%s", "DEF\t");
    tprntf("%d", 34);
    tprntNewLine(); // realloc necessary ...
    tprntf("%s", "GHI\t");
    tprntf("%d", 56);
    tprntNewLine(); // again realloc for testing purposes ...
    printf("tReturnString at the end:\n>%s<\n", tReturnString); // contains trailing newline
    return 0;
}
let myArgs = CStringArray(["computeIt", "par1", "par2"])
let returnString = mymain(myArgs.numberOfElements, &myArgs.pointers[0])

if let itReturns = String.fromCString(returnString) {
    print(itReturns)
}

freeMemory()