将功能,线路,时间信息添加到所有现有的" couts"

时间:2016-01-22 17:13:30

标签: c++ function c++11 overloading function-overriding

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

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

cout<<"This thing does not work";&lt; - 在A.cpp中

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

cout<<"There was a problem reading JHI";&lt; - 在C.cpp

。 。 等等..

在一个大型代码库中,我无法编辑所有现有的couts ..

我需要这些couts打印类似的东西..

cout<<"This thing does not work"<<__FUNCTION__<<__LINE__;&lt; - 在A.cpp中

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

cout<<"There was a problem reading JHI"<<__FUNCTION__<<__LINE__;&lt; - 在C.cpp 。

希望这会让它变得更清楚..我希望原始的couts可以自动转换(通过做一些技巧)转换,这样他们也可以打印这些额外的信息..

2 个答案:

答案 0 :(得分:2)

(您的问题并不完全重复this,因为您还想输出行和源文件信息,àla__FILE__和{{1这会产生重大影响;但是我觉得你的问题有点过于宽泛而且缺乏细节)

自定义编译器

您可以使用GCC MELT(我已设计并实现)自定义最近的GCC编译器以执行您想要的操作。然后,您将编写一个额外的“优化通道”,它会神奇地转换您的__LINE__ ...输出语句(在编译器内),通过使它们等效于builtin expressions > std::cout << ....;您需要在Gimple级别进行适当的转换。

这可能不是一项微不足道的任务,因为您需要了解GCC内部表示的细节。因此,我并不完全确定它是值得的(除非你的代码库至少有五百万的源代码行,并且花费几周的时间来编写你的MELT定制是值得的。)

如果你能负担得起手动编辑每一条相关的行,像here这样的宏观方法可能更简单。

您可以将两者结合起来,使用MELT检测正确的行进行编辑,并将它们反馈到std::cout << __builtin_FILE () << ' ' << __builtin_LINE () << ' ' <<脚本中,从而转换源代码以调用宏。

为什么转型不简单

在内部,编译器可以处理某些内部表示,它是规范化 AST,甚至更简单(Gimple)。对于GCC,您希望转换

内部表示
sed

接近

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

理解 Gimple表示,请使用 extern "C" void transformed_testit (int x) { if (x>0) std::cout << __builtin_FILE() << ' ' << __builtin_LINE() << ' ' << "x=" << x << std::endl; } 进行编译;这是第一个函数的Gimple代码的 textual 转储(实际上,Gimple只是一个 in-memory 数据结构):

g++ -fdump-tree-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, endl);
    goto <D.21755>;
    <D.21752>:
    <D.21755>:
  }     

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

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

甚至

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

(在上面的示例中,两行代码可能相距甚远,甚至在不同的文件中,例如某些头文件中的auto& output = std::cout; output << "x=" << x << std::endl; ,并在某些实现文件中使用...但Gimple表示在所有情况下都非常相似)

因此,纯粹的文本或语法方法并不总是有效,你需要一个类似于编译器的复杂工具来进行转换。

因此,如果您能够花费至少两周的时间来解决问题,请尝试使用GCC MELT。否则,手动运行 某些#define MY_LOG脚本,或者编写您的Emacs功能代码以交互方式编辑

在C ++中作弊

也许你可能有

sed

然后你可以做

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__)

因此,您可以在mycout << "x=" << x << std::endl; ...后尝试#define cout mycout;它可能会泄漏许多错误消息,您可以在其位置手动调整代码

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

答案 1 :(得分:1)

显而易见的解决方案是使用一些编辑器宏,例如vim's macrosgrep -rnw 'directory' -e "cout <<"配对,假设是Linux平台。

关于C ++,如果您在整个代码中使用cout而不是std::cout,那么可能的解决方案就是删除using namespace std然后推出您自己的cout函数 - 假设您没有其他代码,具体取决于std::将会中断。

已将问题标记为重复的问题might contain an answer