3

我有一堆printf()s 可以正确打印我必须构建的非常复杂的字符串。

问题是我需要将该字符串存储在一个变量中(所有这些printf()s 一起通过套接字发送它们的结果。我很确定我需要立即发送它们 - 但我会让一个小窗口如果你想说服我那不是真的,请打开。

实现这一目标的最佳方法是什么?

字符串长度确实是可变的。我听说过sprintf()and realloc(),甚至asprintf(),但我不知道如何将所有这些混合在一起。

这是我当前的代码:

void mostrarVariable(char *variable, void *valor) {
    printf("%s=%d\n", variable, *(int *)valor);
}

void mostrarEntradaStack(t_registro_stack *entradaStack) {
    printf("%d,%s\n", entradaStack->retorno, entradaStack->nombre_funcion);
}

void suspender(t_pcb *pcb) {
    char *mensaje = NULL;
    mensaje = strdup("1Proceso suspendido...");
    // FIXME: guardar los printf en una variable y enviarlo por la red

    printf("----------------\n\n");
    printf("ID=%d\n", pcb->id_proceso);
    printf("PC=%d\n", pcb->program_counter);
    printf("\n-- Estructura de codigo --\n");

    int indice = 0;

    // believe me: this iterates a char** printf-ing each line
    while(pcb->codigo[indice] != NULL) {
        printf("%s\n", pcb->codigo[indice++]);
    }

    printf("----------------\n");
    printf("\n-- Estructuras de datos --\n");

    // believe me: this calls mostrarVariable() for each entry in the pcb->datos dictionary
    dictionary_iterator(pcb->datos, mostrarVariable);

    printf("----------------\n\n");
    printf("-- Estructura de Stack --\n");

    // believe me: this calls mostrarEntradaStack() for each element in the stack without modifying it
    pila_hacer(pcb->stack, mostrarEntradaStack);

    printf("\n----------------\n");

    // believe me: this sends "mensaje" via a socket ("pcb->id_proceso"), and it handles the partial send()s and all of that
   // it has to be on one socket_send() to correctly send the message length to the other endpoint - the protocol pretty works
    socket_send(pcb->id_proceso, mensaje, strlen(mensaje) + 1);
}

相信我,代码目前可以工作,但mensaje只有值“1Proceso suspendido ...”,数据在本地打印,而不是发送到远程。

样本输出:

----------------

ID=4
PC=6

-- Estructura de codigo --
#!/home/desert69/workspaces/operativos/no-quiero/procer/pi/build/pi
# Comentario
variables a,b,c,d,e
comienzo_programa
a=1
b=2;3
c=a+b
d=c-3
f1()
f2()
e=a+c;2
imprimir a
imprimir b
imprimir c
imprimir d
imprimir e
fin_programa
comienzo_funcion f1
a=3
f3()
b=4
fin_funcion f1
comienzo_funcion f2
a=a+1
fin_funcion f2
comienzo_funcion f3
c=d
fin_funcion f3
----------------

-- Estructuras de datos --
c=159769736
d=159769776
a=159769600
b=159769696
e=159769816
----------------

-- Estructura de Stack --

----------------

对不起,西班牙语的代码,但我想确保它与我正在运行的完全相同。也许稍后(如果可以的话)我会尝试翻译它,但我不确定。即使很难,重要的是将every 替换printf()某些东西以将这些输出附加到mensaje.

如果您需要任何进一步的信息,请随时发表评论。

谢谢。真的 :)

4

4 回答 4

2

最简单的方法是连接一堆sprintf语句。忽略错误条件,该语句返回写入的字符数。所以你基本上可以这样做:

char *bufptr = buffer;
bufptr += sprintf( bufptr, "ID=%d\n", pcb->id_proceso );
bufptr += sprintf( bufptr, "PC=%d\n", pcb->program_counter );

ETC

然后buffer包含从对 的连续调用构建的字符串sprintf。显然,您需要确保缓冲区足够大。如果您预计会出现错误,您还应该处理错误。

此外,您可以使用 获得字符串的最终长度bufptr - buffer,这对于了解您是否通过套接字发送它很有用。

于 2012-11-26T01:06:12.893 回答
0

您可以在该缓冲区中创建一个大的buffer所有数据。sprintf()

char buffer[20000];    // large enough
char str[500];         // temporary string holder

buffer[0] = '\0';      // clean up the buffer
sprintf( str, "----------------\n\n");            strcat( buffer, str);
sprintf( str, "ID=%d\n", pcb->id_proceso);        strcat( buffer, str);
sprintf( str, "PC=%d\n", pcb->program_counter);   strcat( buffer, str);
sprintf( str, "\n-- Estructura de codigo --\n");  strcat( buffer, str);

... 等等

于 2012-11-26T01:05:36.007 回答
0

我终于创建了一个string_concat()函数,它接收一个original字符串、一个格式和一个变量参数列表,并将 avsnprintf与格式和参数一起应用,并将其附加到原始字符串:

编辑:好的,所以我以前的方法是错误的。va_list我认为有问题。这是新版本:

/**
 * @NAME: string_append
 * @DESC: Agrega al primer string el segundo
 *
 * Ejemplo:
 * char *unaPalabra = "HOLA ";
 * char *otraPalabra = "PEPE";
 *
 * string_append(&unaPalabra, otraPalabra);
 *
 * => unaPalabra = "HOLA PEPE"
 */
void string_append(char** original, char* string_to_add) {
        *original = realloc(*original, strlen(*original) + strlen(string_to_add) + 1);
        strcat(*original, string_to_add);
}

/**
 * @NAME: string_concat
 * @DESC: Concatena al primer string el resultado de aplicar los parametros al
 * formato especificado
 *
 * Ejemplo:
 * char *saludo = "HOLA ";
 * char *nombre = "PEPE";
 *
 * string_concat(&saludo, "%s!", nombre);
 *
 * => saludo = "HOLA PEPE!"
 */
void string_concat(char **original, const char *format, ...) {
    size_t buffer_size = strlen(format) + 1;
    char *temporal = malloc(buffer_size);
    size_t message_length = 0;
    va_list arguments;
    va_start(arguments, format);
    while((message_length = vsnprintf(temporal, buffer_size, format, arguments)) > buffer_size - 1) {
        buffer_size *= 2;
        temporal = (char *) realloc(temporal, buffer_size);
    }
    va_end(arguments);
    temporal = (char *) realloc(temporal, message_length + 1);

    string_append(original, temporal);
}

string_append()仍在泄漏内存(由于realloc()),我希望能管理后者。


错误代码从这里开始

/**
 * @NAME: string_append
 * @DESC: Appends the second string to the first
 *
 * Example:
 * char *aWord = "Hello, ";
 * char *anotherWord = "world!";
 *
 * string_append(&aWord, anotherWord);
 *
 * => aWord = "Hello, world!"
 */
void string_append(char** original, char* string_to_add) {
    *original = realloc(*original, strlen(*original) + strlen(string_to_add) + 1);
    strcat(*original, string_to_add);
}

/**
 * @NAME: string_concat
 * @DESC: Concatenates to the first string the result of applying the arguments to 
 * the specified format
 *
 * Example:
 * char *salute = "Hello";
 * char *name = "world";
 *
 * string_concat(&salute, ", %s!", name);
 *
 * => salute = "Hello, world!"
 */
void string_concat(char **original, const char *format, ...) {
    size_t buffer_size = strlen(format) + 1;
    char *temporal = malloc(buffer_size);
    size_t message_length = 0;
    va_list arguments;
    va_start(arguments, format);
    while((message_length = vsnprintf(temporal, buffer_size, format, arguments)) > buffer_size - 1) {
        buffer_size *= 2;
        temporal = (char *) realloc(temporal, buffer_size);
    }
    va_end(arguments);
    temporal = (char *) realloc(temporal, message_length + 1);

    string_append(original, temporal);
}

错误代码结束

我以前是string_append()我的分配存储库中获得的。

我认为它没有内存泄漏/问题,但还没有真正测试过那么多。但是对我有用,至少在我在原始问题中展示的示例中。

所以这是我之前展示的代码的最终版本:

void suspender(t_pcb *pcb) {
    char *mensaje = NULL;
    mensaje = strdup("1Proceso suspendido...\n\n");

    string_concat(&mensaje, "----------------\n\n");
    string_concat(&mensaje, "ID=%d\n", pcb->id_proceso);
    string_concat(&mensaje, "PC=%d\n", pcb->program_counter);
    string_concat(&mensaje, "\n-- Estructura de codigo --\n");

    int indice = 0;

    while(pcb->codigo[indice] != NULL) {
        string_concat(&mensaje, "%s\n", pcb->codigo[indice++]);
    }

    string_concat(&mensaje, "----------------\n");
    string_concat(&mensaje, "\n-- Estructuras de datos --\n");

    // TODA la magia negra junta: inner functions!! (?!!?!?!)
    void mostrarVariableEnMensaje(char *variable, void *valor) {
        string_concat(&mensaje, "%s=%d\n", variable, *(int *)valor);
    }

    dictionary_iterator(pcb->datos, mostrarVariableEnMensaje);

    string_concat(&mensaje, "----------------\n\n");
    string_concat(&mensaje, "-- Estructura de Stack --\n");

    void mostrarEntradaStackEnMensaje(t_registro_stack *entradaStack) {
        string_concat(&mensaje, "%d,%s\n", entradaStack->retorno, entradaStack->nombre_funcion);
    }

    pila_hacer(pcb->stack, mostrarEntradaStackEnMensaje);

    string_concat(&mensaje, "\n----------------\n");


    socket_send(pcb->id_proceso, mensaje, strlen(mensaje) + 1);
    free(mensaje);
}
于 2012-11-26T07:29:06.020 回答
0

乍一看似乎很微不足道。在每个步骤中,您都附加了一个字符串或一个 int。前者可以简化为后者

char tmp[100];
snprintf(tmp, sizeof tmp - 1, "%d", n);
append_string(tmp);  // pseudo-code

因此,您所需要的只是一种将字符串附加到另一个字符串的方法。这可以通过 、 、 或 的strlen组合reallocstrcpy完成memcpy

更大的问题是您的dictionary_iteratorpila_hacer函数似乎不允许您将任何其他信息传递给回调。printf不在乎,因为它可以只使用 global stdout,但是如果你想让它附加到一个字符串,你可能需要在这里使用一个全局变量,所以你的回调知道在哪里附加。

于 2012-11-26T01:08:34.207 回答