3

printf()作成する必要のある非常に複雑な文字列を正しく出力するsがたくさんあります。

問題は、その文字列を変数に格納する必要があることです(printf()ソケットを介して送信するために、これらすべての文字列をまとめた結果です。一度に送信する必要があると確信していますが、小さなウィンドウを表示しますあなたが私を説得したいのなら、それは真実ではありません。

それを達成するための最良の方法は何ですか?

文字列の長さは本当に可変です。sprintf()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 --

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

スペイン語のコードで申し訳ありませんが、私が実行しているものとまったく同じものであることを確認したかったのです。たぶん後で(できれば)私はそれを翻訳しようとしますが、よくわかりません。難しい場合でも、重要なことは、それらの出力をに追加するために、すべて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 );

次に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

一見するとかなり些細なことに見えます。各ステップで、文字列または整数のいずれかを追加します。前者は後者に還元することができます

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

したがって、必要なのは、ある文字列を別の文字列に追加する方法だけです。これは、、、、、またはの組み合わせstrlenで実行できます。reallocstrcpymemcpy

より大きな問題は、あなたの関数dictionary_iteratorpila_hacer関数では、コールバックに追加情報を渡せないように見えることです。printfグローバルを使用できるので気にしませんstdoutが、文字列に追加する場合は、おそらくここでグローバル変数を使用する必要があるため、コールバックはどこに追加するかを認識します。

于 2012-11-26T01:08:34.207 に答える
0

私はついに、文字列、フォーマット、および可変引数リストstring_concat()を受け取り、フォーマットと引数を適用して、それを元の文字列に追加する関数を作成しました。originalvsnprintf

編集:わかりました、それで私の以前のアプローチはバグがありました。問題があった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 に答える