[C]progress bar

MarcoHensel

Well-Known Member
hey Ihr,

ich hab da mal was vorbereitet:
Code:
#include <stdio.h>

void print_progress(int count,int i)
{
        int tmpi=i;
        int tmpy=count-i;
        char *t="#";

        printf("Progress: ");
        while ( tmpi > 0 )
        {
                printf("%s", t);
                --tmpi;
        }
        while ( tmpy > 0 )
        {
                printf("%s", ".");
                --tmpy;
        }
        printf(" %d%%", i);
        fflush(stdout);
        printf("\r");
}


void main()
{
        int i;
        int count=100;

        for(i=0;i<=count;i++)
        {
                print_progress(count,i);
                usleep(60000);
        }

        printf("\n\n");

}

Funktioniert soweit, aber ich hab so ein Gefuehl das es wesentlich kuerzer/eleganter geht. Vllt. kann mir jemand diesbezueglich was zeigen.

Viele Gruesse,

Marco
 
Ich habe mal den Code leicht angepasst und Kommentare dran geschrieben und nur lästig Formfehler behoben ohne größere Änderungen vorzunehmen.
Code:
#include <stdio.h>
// TODO: Include all required headers
#include <unistd.h>

// TODO: Rename the second parameter (i is normally used as count variable in (for) loops).
// Should this function handle terminals smaller or much larger than an unscaled progress bar?
void
print_progress(int count, int index)
{
        int  tmpi = index;
        int  tmpy = count - index;
        char *t    = "#";

        printf("Progress: ");
        while ( tmpi > 0 ) {
                printf("%s", t);
                --tmpi;
        }
        while ( tmpy > 0 ) {
                printf("%s", ".");
                --tmpy;
        }
    // TODO: Rethink the percent sign.
    // It implies that count should always equal 100.
    // This makes the count parameter redundant.
        printf(" %d%%", index);
        fflush(stdout);
        printf("\r");
}

// TODO: Encapsulate ignoring arguments in a macro.
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif /* defined(UNUSED) */

// TODO: Fix main functions signature
int
main(int argc, char *argv[])
{
    // TODO: Keep even the most annoying compilers happy
    // by consuming the arguments to main.
    UNUSED(argc);
    UNUSED(argv);

        const int count = 100;

    // TODO: Move i into the minimal scope required
    //
    // The API lends it self to a very tight coupling of application logic and user-interface.
    // Is this this the right trade-off?
        for ( int i = 0; i <= count; i++ ) {
                print_progress(count, i);
                usleep(60000);
        }

        printf("\n\n");

    // TODO: Return an exit code.
    return 0;
}

Ich würde die while Schleifen durch eine for Schleife ersetzen. Printf() einmal pro Zeichen in den Schleifen aufzurufen erzeugt zwar einen hohen Overhead der ist jedoch meiner Meinung nach die Vereinfachung wert. Wobei ich doch gestehen muss dazu zu neigen einen Variabel großen Buffer auf dem Stack anzulegen und in mit memcpy() und memset() zu befüllen.

Für einfache Anwendungen ist die einfache API sinnvoll. Für komplizierte Anwendungen solltest du drüber nachdenken wie du das UI am besten von der Logik getrennt halten kannst. So eine Update schleife hätte in der main Funktion einer Anwendung nix verloren, weil dabei zu unterschiedliche Abstraktionslevel gemischt werden. Dies bricht den Nutzen der hoffentlich vorhandenen funktionalen Abstraktionen.
 
Das Erkennen der Breite des Terminals -- statt der fest eingebauten 80 -- überlasse ich dem geneigten Leser als Übungsaufgabe.

Code:
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static void print_progress(FILE* const out, char const* const label, unsigned const idx, unsigned const max)
{
  assert(idx <= max);

  fprintf(out, "\r%s: ", label);

  unsigned const wMax = 80 - strlen(label) - 2 /* ": " */ - 6 /* " xxx% " */;
  unsigned const wIdx = wMax * idx / max;
  unsigned       i    = 0;
  for (; i != wIdx; ++i)
    fputc('#', out);
  for (; i != wMax; ++i)
    fputc('.', out);

  fprintf(out, " %3u%%", 100 * idx / max);

  fflush(out);
}

int main(void)
{
  FILE*    const out = stdout;
  unsigned const max = 42;
  for (unsigned i = 0; i <= max; ++i) {
    print_progress(out, "Progress", i, max);
    usleep(100000);
  }
  fputc('\n', out);
  return 0;
}
 
Zurück
Oben