2 Stimmen

Drucken auf dem Bildschirm und einer Textdatei

Ich muss bestimmte Dinge in eine Textdatei schreiben und diese auf dem Bildschirm anzeigen lassen. (Ich spreche von einem C-Programm-Utility) Der Menüpunkt sieht wie folgt aus,

1\. display AA parameters
2. display BB parameters
3. display CC parameters
4. dump all
5. Exit
Select option >

Wenn sie 1/2/3 auswählen, muss es nur auf dem Bildschirm angezeigt werden, oder wenn sie die Option #4 auswählen, müssen alle Parameter einzeln angezeigt werden, und dasselbe muss in einer .txt-Datei gespeichert werden.

Ich weiß, dass wir die Funktionen printf und fprintf verwenden können, um sie auf dem Bildschirm anzuzeigen bzw. in eine Textdatei zu schreiben. Das Problem ist, dass ich mehr als 20 Parameter angezeigt habe und jeder mindestens 20 Unterparameter hat.

Ich bin derzeit wie folgt implementiert,

printf (        "Starting serial number       [%ld]\n", 
        serial_info_p->start_int_idx);
fprintf(file_p, "Starting serial number       [%ld]\n", 
        serial_info_p->start_int_idx)
printf (        "Current Serial number         [%d]\n", 
        serial_info_p->current_int_idx);
fprintf(file_p, "Current Serial number         [%d]\n", 
        serial_info_p->current_int_idx);

Gibt es einen einfachsten Weg, dies zu implementieren, um die Anzahl der Codezeilen zu reduzieren?

6voto

Giacomo Punkte 10677

Bearbeiten: das C++-Tag scheint irreführend zu sein, kann es jemand bitte entfernen? danke :)

Ich verwende variadische Makros, um printf und Co. anzupassen.

Ich würde etwa so schreiben:

#define     tee(fp,fmt, ...)                             \
        {                                                \
                printf (fmt, __VA_ARGS__);               \
                fprintf (fp, fmt, __VA_ARGS__);          \
        }

(der Name stammt von dem Dienstprogramm tee(1))

3voto

Eclipse Punkte 43775

Auf diese Weise können Sie eine beliebige Anzahl von Ausgabeströmen hinzufügen und sie zur Laufzeit ändern, indem Sie einfach die verknüpfte Liste PrintTarget ändern.

/** gcc -Wall -o print_target print_target.c && ./print_target */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct PrintTarget* PrintTargetp;

void* xmalloc (size_t size);
PrintTargetp pntCreate (PrintTargetp head, FILE* target);
void pntDestroy (PrintTargetp list);

typedef struct PrintTarget
{
  FILE* target;
  PrintTargetp next;
} PrintTarget;

void myPrintf (PrintTargetp streams, char* format, ...)
{
  va_list args; 
  va_start(args, format);
  while (streams)
    {
      vfprintf(streams->target, format, args);
      streams = streams->next;
    }
  va_end(args);
}

int main(void)
{
  PrintTargetp streams = pntCreate(NULL, stdout);
  streams = pntCreate(streams, fopen("somefile.txt", "a+")); //XXX IO errors?

  myPrintf(streams, "blah blah blah...\n");
  pntDestroy(streams);
  return 0;
}

Hier ist eine Definition der Hilfsfunktionen:

PrintTargetp pntCreate (PrintTargetp head, FILE* target)
{
  PrintTargetp node = xmalloc(sizeof(PrintTarget));
  node->target = target;
  node->next   = head;
  return node;
} 

void pntDestroy (PrintTargetp list)
{
  while (list) 
    {
      PrintTargetp next = list->next;
      free(list);
      list = next;
      //XXX cycles?
      //XXX close files?
    }
}

void* xmalloc (size_t size)
{
  void* p = malloc(size);
  if (p == NULL)
    {
      fputs("malloc error\n", stderr);
      abort();
    }
  return p;
}

2voto

Adam Rosenfield Punkte 373807

Sie könnten auch einfach die Ausgabe Ihres Prorgams an die tee(1) Befehl.

1voto

MattK Punkte 10147

Wenn Sie eine Konsolenanwendung schreiben, sollten Sie in der Lage sein, die Ausgabe auf dem Bildschirm (Standardausgabe) mit etwas wie:

fprintf(stdout, "Hello World\n");

Dies sollte es Ihnen ermöglichen, den Code, der Ihre Daten druckt, in eine eigene Funktion zu verschieben und eine DATEI* zu übergeben, in die er gedruckt werden soll. Dann kann die Funktion auf den Bildschirm drucken, wenn Sie "stdout" übergeben, oder in eine Datei, wenn Sie eine andere DATEI* übergeben, z.B.:

void print_my_stuff(FILE* file) {
    fprintf( file,"Starting serial number       [%ld]\n", serial_info_p->start_int_idx);
    fprintf(file, "Current Serial number         [%d]\n", serial_info_p->current_int_idx);
    .
    .
    .
}

1voto

Matthew Crumley Punkte 98564

Bearbeiten: Ich habe nicht bemerkt, dass Sie eine C-Lösung benötigen. Ich lasse diese Antwort als Referenz da, aber sie erfordert offensichtlich C++.

Sie könnten eine neue Stream-Klasse erstellen, die die Ausgabe an zwei Streams sendet. Ich fand eine Implementierung dieser Klasse unter http://www.cs.technion.ac.il/~imaman/programme/teestream.html . Ich habe es nicht ausprobiert, aber es sollte funktionieren.

Hier ist der Code aus dem Link:

#include <iostream>
#include <fstream>

template<typename Elem, typename Traits = std::char_traits<Elem> >
struct basic_TeeStream : std::basic_ostream<Elem,Traits>
{
   typedef std::basic_ostream<Elem,Traits> SuperType;

   basic_TeeStream(std::ostream& o1, std::ostream& o2) 
      :  SuperType(o1.rdbuf()), o1_(o1), o2_(o2) { }

   basic_TeeStream& operator<<(SuperType& (__cdecl *manip)(SuperType& ))
   {
      o1_ << manip;
      o2_ << manip;
      return *this;
   }

   template<typename T>
   basic_TeeStream& operator<<(const T& t)
   {
      o1_ << t;
      o2_ << t;
      return *this;
   }

private:
   std::ostream& o1_;
   std::ostream& o2_;
};

typedef basic_TeeStream<char> TeeStream;

Sie würden es so verwenden:

ofstream f("stackoverflow.txt");
TeeStream ts(std::cout, f);
ts << "Jon Skeet" << std::endl; // "Jon Skeet" is sent to TWO streams

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X