0

I already have a large code base that uses a lot of couts. I cannot go and change all the existing couts. Is there something I can do so that, the existing couts add FUNCTION , LINE and time information along with what needs to be printed in the cout? In otherwords can I override cout to use my implementationwhich will print the string along with all the extra information. I am open to doing anything else too, not necessarily overriding..

Maybe I didnt explain clearly.. This is what I need. I already have stuff like,

cout<<"This thing does not work"; <-- In A.cpp

cout<<"This thing does works but the problem is XYZ"; <-- In B.cpp

cout<<"There was a problem reading JHI"; <-- In C.cpp

. . and so on..

in a large code base in which I CANNOT edit all the existing couts..

I would need these couts to print something similar to..

cout<<"This thing does not work"<<__FUNCTION__<<__LINE__; <-- In A.cpp

cout<<"This thing does works but the problem is XYZ"<<__FUNCTION__<<__LINE__; <-- In B.cpp

cout<<"There was a problem reading JHI"<<__FUNCTION__<<__LINE__; <-- In C.cpp . .

Hope this makes it clearer.. I want the original couts to be AUTOMATICALLY(by doing some trick maybe) transformed so that they also print this extra information..

quickdraw
  • 247
  • 1
  • 2
  • 12
  • 4
    No, you can't override `cout`. But you can glob replace it with something like 'my_cout' (there are tools), which will be a macro. – SergeyA Jan 22 '16 at 17:14
  • I cannot replace all the existing "cout" to "my_cout" or similar, thats not an option.. I would like to add information to existing couts – quickdraw Jan 22 '16 at 17:18
  • 3
    Sorry, you are out of luck here. I'd never suggest `#defin`ing `cout`. – SergeyA Jan 22 '16 at 17:19
  • Could you give an example? What you want is not clear. – Basile Starynkevitch Jan 22 '16 at 17:32
  • 1
    [std::basic_ios::rdbuf](http://en.cppreference.com/w/cpp/io/basic_ios/rdbuf). & Think next time **before** introducing dependencies on global variables. – Ivan Aksamentov - Drop Jan 22 '16 at 17:34
  • @Drop: "dependencies on global variables"? What are you talking about? – DevSolar Jan 22 '16 at 17:44
  • 1
    @DevSolar [`std::cout`](http://en.cppreference.com/w/cpp/io/cout) is a global variable. What is your question exactly? – Ivan Aksamentov - Drop Jan 22 '16 at 17:52
  • @Drop how would you make a custom streambuf insert the file/line number info? (Hint: it's not possible without the macro) – sehe Jan 22 '16 at 20:42
  • 1
    From a management point of view, "I can't change the existing couts" does not gel with "I can change what the existing couts do". Do you not have any semblance of stability control in your codebase? That's a _massive_ contract violation, far more severe than if you actually replaced the original calls in the code. There's no way I'd accept it in code review. Just sayin'. – Lightness Races in Orbit Jan 23 '16 at 03:41
  • What I am saying is that I cannot MANUALLY go and change each and every cout in the code, I would like a solution for it to be automated.. Does it gel now? – quickdraw Jan 23 '16 at 03:43
  • How large is your code base (ten thousand sources lines or ten millions source lines)? Is *every* relevant output line exactly formatted as `std::cout <<` or is it sometimes `cout <<` etc..? What compiler (and version), what operating system... – Basile Starynkevitch Jan 23 '16 at 06:37
  • @Ram: you could contact me privately by email (give the URL of your question, and describe more your problem, your entire code base, your company, your country, etc...) to `basile@starynkevitch.net` – Basile Starynkevitch Jan 23 '16 at 07:15

2 Answers2

2

(your question is not exactly duplicate of this because you also want to output line & source file information, à la __FILE__ and __LINE__, and that makes a significant difference; however I feel that your question is a bit too broad and is lacking details)

customizing your compiler

You might customize a recent GCC compiler to do what you wish using GCC MELT (which I have designed & implemented). You'll then code an additional "optimization pass" which would magically transform your std::cout << ... output statements (inside the compiler) adding some builtin expressions by making them the equivalent of std::cout << __builtin_FILE () << ' ' << __builtin_LINE () << ' ' << ....; you'll need to make the appropriate transformation at the Gimple level.

It is probably not a trivial task, since you'll need to understand the details of GCC internal representations. Therefore, I'm not entirely sure it is worthwhile (unless your code base has at least half a millions of source code line, and spending a couple of weeks to write your MELT customization is worthwhile).

If you can afford to manually edit every relevant line, a macro approach like here is perhaps simpler.

You could perhaps combine both, using MELT to detect the right lines to edit and feed them into a sed script transforming your source code to invoke a macro.

why the transformation is not simple

Internally, a compiler works on some internal representation which is a normalized AST, or even something simpler (Gimple). For GCC, you want to transform the internal representation of

 extern "C" void testit(int x) {
   if (x>0)
   std::cout << "x=" << x << std::endl;
 }

into something close to the internal representation of

 extern "C" void transformed_testit (int x) {
   if (x>0)
     std::cout << __builtin_FILE() << ' ' << __builtin_LINE() << ' ' 
               << "x=" << x << std::endl;
 }    

To understand the Gimple representation, compile these with g++ -fdump-tree-gimple ; here is the textual dump of the Gimple code of the first function (actually, Gimple is only an in-memory data structure):

  void testit(int) (int x)
  {
    struct basic_ostream & D.21753;
    struct basic_ostream & D.21754;

    if (x > 0) goto <D.21751>; else goto <D.21752>;
    <D.21751>:
    D.21753 = std::operator<< <std::char_traits<char> > (&cout, "x=");
    D.21754 = std::basic_ostream<char>::operator<< (D.21753, x);
    std::basic_ostream<char>::operator<< (D.21754, endl);
    goto <D.21755>;
    <D.21752>:
    <D.21755>:
  }     

why you need to work inside the compiler

Because your source code may contains such output in many variants, including

std::cout << "x=" << x << std::endl;

or

using namespace std;
cout << "x=" << x << endl;

or

#define MY_LOG(Out) do{std::cout<<Out<<std::endl;} while(0)
MY_LOG("x=" << x);

or even

auto& output = std::cout;
output << "x=" << x << std::endl;

(in the examples above, the two lines of code might be very far apart, or even in different files, e.g. the #define MY_LOG in some header file, and used in some implementation file... But the Gimple representation would be very similar in all cases)

hence a purely textual or syntactic approach won't always work, and you need a complex tool, similar to a compiler, to do the transform.

So, if you can afford spending at least two weeks of your work to solve your issue, try using GCC MELT. Otherwise, run manually some sed script, or code your Emacs function to do that edit interactively

cheating in C++

Maybe you might have

struct myoutputat {
 const char*fil;
 int lin;
 myoutputat(const char*f, int l) : fil(f), lin(l) {};
 std::ofstream& operator << (const char*msg) { 
   std::cout << f << ' ' << l << msg;
   return std::cout;
 }
}; // end of myoutputat
#define mycout myoutputat(__FILE__,__LINE__)

then you might do

mycout << "x=" << x << std::endl;

Hence you could try #define cout mycout after the #define mycout...; it probably would spill many error messages, and you could manually tweak the code at their location

PS. You can contact me by private email to basile@starynkevitch.net but then please mention the URL of your question and give much more details: what is your code doing, what is its source size, what exact compiler you are using, what is your employer & country, etc...

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

The obvious solution would be to use some editor macro, such as vim's macros paired with a grep -rnw 'directory' -e "cout <<", assuming a Linux platform.

Regarding C++, if you are using cout and not std::cout throughout your code, then a possible solution would be to remove your using namespace std and then rollout your own cout function - assuming you don't have other code depending on std:: which will break.

The question which has been marked as a duplicate, might contain an answer to your problem.

Community
  • 1
  • 1
Ælex
  • 14,432
  • 20
  • 88
  • 129