将FUNCTION,LINE,时间信息添加到所有现有的“cout” [英] Add FUNCTION, LINE, time information to all existing "couts"

查看:380
本文介绍了将FUNCTION,LINE,时间信息添加到所有现有的“cout”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经有一个大的代码库,使用了很多couts。
我不能去改变所有现有的couts。
我可以这样做,现有的couts添加 FUNCTION LINE 和时间信息以及需要在cout中打印什么?换句话说,我可以覆盖cout使用我的实现,它将打印字符串以及所有的额外信息。
我也愿意做任何其他事情,不一定要重写。



也许我没有解释清楚..
这是我需要的。我已经有类似的东西,



cout<<这件事不起作用; 在A.cpp



cout<<这个东西确实有效,但问题是XYZ; - 在B.cpp



cout<<读取JHI时出现问题; - 在C.cpp





等等。



在一个大代码库中,我不能编辑所有现有的couts ..



我需要这些cout打印类似于..



cout<<这个东西不工作 ;< __ FUNCTION __<< __ LINE __; < - 在A.cpp



cout<这个问题是可行的,但问题是XYZ< <__ FUNCTION __ <__ LINE __; < - 在B.cpp



< cout<<在Ccpp
中读取JHI< __ FUNCTION __< __ LINE __;



希望这使它更清晰..我想原来的couts是自动的(通过做一些技巧也许)转换,使他们也打印这个额外信息..

解决方案

(您的问题不完全 http://stackoverflow.com/questions/18975512/how-to-override-cout-in-c\">这是,因为您也想输出行和源文件信息,àla __ FILE __ __ LINE __ ,这有一个明显的区别,但我觉得你的问题有点太宽泛, / sup>



自定义编译器



您可以自定义最近的GCC编译器, a href =http://gcc-melt.org/ =nofollow> GCC MELT (我已经设计和实现)。然后,您将编写一个额外的优化传递,将神奇地转换您的 std :: cout ...输出语句a href =https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html =nofollow>内建表达式,使其成为 code> std :: cout<< __builtin_FILE()<< ''<< __builtin_LINE()<< ''<< / code> ...;您需要在 Gimple 级别进行适当的转换。



这可能不是一个简单的任务,因为你需要了解GCC内部表示的细节。因此,我不完全确定这是值得的(除非你的代码基础至少有50万个源代码行,花费几个星期来编写你的MELT定制是值得的)。



如果您能够手动编辑每个相关行,则像这里这样的宏方法可能更简单。



您可以结合两者,使用MELT检测正确的行,然后将它们编辑为 sed



为什么变换不简单



在内部,编译器在一些规范化的 内部表示上工作 AST ,或者甚至更简单(Gimple)。对于GCC,您要转换

内部表示

$ test $($)

  extern x){
if(x> 0)
std :: cout<< x =<< x<< std :: endl;
}

/ p>

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

了解 Gimple表示, g ++ -fdump-tree-gimple ;这里是第一个函数(实际上,Gimple只是一个内存中的数据结构)的Gimple代码的文本转储:

  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,end1);
goto< D.21755> ;;
< D.21752> ;:
< D.21755> ;:
}


b $ b

为什么需要在编译器中工作



因为您的源代码可能包含许多变体的输出,包括

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

 c $ c> using namespace std; 
cout<< x =<< x<< endl;

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

或甚至

 code> auto& output = std :: cout; 
output<< x =<< x<< std :: endl;

(在上面的示例中,两行代码可能相隔很远,即使在不同的文件中,例如在一些头文件中的 #define MY_LOG ,并且在一些实现文件中使用...但是Gimple表示将在所有情况下非常相似) / sup>



因此,纯文本或语法方法并不总是起作用,您需要一个类似于编译器的复杂工具来完成转换。 p>

因此,如果您能负担至少两个星期的工作来解决您的问题,请尝试使用GCC MELT。否则,请手动运行 一些 sed 脚本,或者对Emacs函数进行编码以

b
$ b

在C ++中作弊



也许你可能有

  struct myoutputat {
const char * fil;
int lin;
myoutputat(const char * f,int l):fil(f),lin(l){};
std :: ofstream&运算符<< (const char * msg){
std :: cout< f<< ''<< 1<< msg;
return std :: cout;
}
}; // end of myoutputat
#define mycout myoutputat(__ FILE __,__ LINE__)

do

  mycout< x =<< x<< std :: endl;因此,您可以尝试 #define cout mycout  


之后的 #define mycout ...;它可能会溢出许多错误消息,你可以手动调整代码在他们的位置



PS。您可以通过私人电子邮件与 basile@starynkevitch.net 联系,但请提供您的问题的网址,并提供更多详细信息:什么是你的代码在做什么,它的源大小,什么确切的编译器,你使用,什么是你的雇主&国家等...


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..

解决方案

(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...

这篇关于将FUNCTION,LINE,时间信息添加到所有现有的“cout”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆