如何在我的程序中找到" const char * + int"表达

时间:2014-07-12 13:10:14

标签: c++ c migration vb6-migration

我在源代码迁移中,转换器程序没有将嵌入字符串的串联转换为整数。现在我有很多代码用这种表达式:

f("some text" + i);

由于C / C ++会将此解释为数组下标,f将收到"some text""ome text""me text" ...

我的源语言将字符串的串联转换为字符串连接。现在我需要逐行浏览源代码并手动将前一个表达式更改为:

f("some text" + std::to_string(i));

转化计划设法转换本地" String"变量到" std::string",产生表达式:

std::string some_str = ...;
int i = ...;

f(some_str + i);

这些很容易修复,因为有了这样的表达式,C ++编译器会输出错误。

是否有任何工具可以在源代码中自动找到这样的表达式?

9 个答案:

答案 0 :(得分:8)

轻松!只需将所有+替换为-&

即可
find . -name '*.cpp' -print0 | xargs -0 sed -i '' 's/+/-\&/g'


在尝试编译项目时,您会在其他错误之间看到类似这样的内容:

foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
    return f(s -& i);
             ~ ^~~~

(我使用clang,但其他编译器应该发出类似的错误)


因此,您只需过滤编译器输出以仅保留这些错误:

clang++ foo.cpp 2>&1 | grep -F "error: 'const char *' and 'int *' are not pointers to compatible types"

你得到:

foo.cpp:9:16: error: 'const char *' and 'int *' are not pointers to compatible types
foo.cpp:18:10: error: 'const char *' and 'int *' are not pointers to compatible types

答案 1 :(得分:7)

您可以尝试flint,这是在Facebook开发和使用的C ++开源lint程序。它具有列入黑名单的令牌序列功能(checkBlacklistedSequences)。您可以将令牌序列添加到checkBlacklistedSequences功能,flint会报告它们。

checkBlacklistedSequences函数中,我添加了序列string_literal + number

BlacklistEntry([tk!"string_literal", tk!"+", tk!"number"],
               "string_literal + number problem!\n",
                true),

然后编译并测试

$ cat -n test.cpp
 1  #include <iostream>
 2  #include <string>
 3  
 4  using namespace std;
 5  
 6  void f(string str)
 7  {
 8      cout << str << endl;
 9  }
10  
11  int main(int argc, char *argv[])
12  {
13      f("Hello World" + 2);
14  
15      f("Hello World" + std::to_string(2));
16  
17      f("Hello World" + 2);
18  
19      return 0;
20  }

$ ./flint test.cpp 
test.cpp(13): Warning: string_literal + number problem!
test.cpp(17): Warning: string_literal + number problem!

flint有两个版本(旧版本用C ++开发,新版本用D语言开发),我在D版本中进行了更改。

答案 2 :(得分:3)

我不熟悉很多可以做到这一点的工具,但我认为grep在某些方面可能会有所帮助。

在源代码的根目录中,尝试:

grep -rn '".\+"\s*+\s*' .

,它可以找出包含像"xxxxx" +这样的行的所有文件,希望这可以帮助您找到所需的所有行。

如果所有整数都是常数,则可以将grep experssion改为:

grep -rn '".\+"\s*+\s*[0-9]*' .

您还可以在字符串常量之前包含(

grep -rn '(".\+"\s*+\s*[0-9]*' .

这可能不是“正确”的答案,但我希望这可以帮到你。

答案 3 :(得分:2)

您可能不需要外部工具。相反,您可以利用C ++单用户定义转换规则。基本上,您需要将f函数的参数从const char* / std::string更改为只能从字符串文字(const char[size])隐式转换的类型或std::string实例(在表达式中添加std::to_string时获得的内容)。

#include <string>
#include <iostream>

struct string_proxy
{
    std::string value;

    string_proxy(const std::string& value) : value(value) {}

    string_proxy(std::string&& value) : value(std::move(value)) {}

    template <size_t size>
    string_proxy(const char (&str)[size]) : value(str) {}
};

void f(string_proxy proxy)
{
    std::cout << proxy.value << std::endl;
}

int main()
{
    f("this works"); // const char[size]
    f("this works too: " + std::to_string(10)); //  std::string
    f("compile error!" + 10); // const char*
    return 0;
}

请注意,这在MSVC上无法运行,至少在2012版本中没有;它可能是一个错误,因为也没有发出警告。它在g ++和clang中运行得非常好(你可以快速检查它here)。

答案 4 :(得分:2)

我找到了一种非常简单的方法来检测这个问题。正则表达式和lint不匹配更复杂的表达式,如下所示:

f("Hello " + g(i));

我需要的是以某种方式进行类型推断,所以我让编译器去做。使用std::string而不是文字字符串会引发错误,因此我wrote a simple source code converter将所有字​​符串文字转换为包装std::string版本,如下所示:

f(std::string("Hello ") + g(i));

然后,在重新编译项目后,我会看到所有错误。源代码在GitHub上,有48行Python代码:

https://gist.github.com/alejolp/3a700e1730e0328c68de

答案 5 :(得分:0)

如果您的情况与

完全相同
"some text in quotations" + a_numeric_variable_or_constant

然后Powergrep或类似的程序将允许您扫描所有文件

("[^"]+")\s*\+\s*(\w+)

并替换为

\1 + std::to_string(\2)

这将为您带来可能的匹配,但我强烈建议您首先预览您要替换的内容。因为这也会替换字符串变量。

正则表达式无法理解代码的语义,因此如果它们是整数,则无法确定它们。为此,您需要一个带有CDT或静态代码分析器等解析器的程序。但不幸的是,我不知道有什么可以做到这一点。总而言之,我希望正则表达式有所帮助:)

PS:对于最坏的情况,如果变量不是数字,那么编译器会给你错误,因为to_string函数不接受任何数字值。可能稍后您可以手动替换它们,我只能希望它们不会更多。

PS 2:有些人可能认为Powergrep价格昂贵。您可以使用试用版15天,并具有完整功能。

答案 6 :(得分:0)

您可以试试Map-Reduce Clang插件。 该工具是在谷歌开发的,只进行这种重构,混合了强类型检查和正则表达式。

(见视频演示here)。

答案 7 :(得分:0)

您可以使用C ++类型转换操作符&amp;创建一个新的类,可以超出操作员+您的需要。您可以将int替换为新类&#34; Integer&#34; &安培;执行所需的重载。这不需要在主函数调用中进行任何更改或单词替换。

class Integer{
    long  i;
    std::string formatted;
public:
     Integer(int i){i = i;}
     operator char*(){
        return (char*)formatted.c_str();}
     friend Integer operator +( char* input, Integer t);
};
Integer operator +( char* input, Integer integer) {
    integer.formatted = input + std::to_string(integer.i);
    return integer;
}
Integer i = ....
f("test" + i); //executes the overloaded operator

答案 8 :(得分:0)

我假设函数f(some_str + i);你的定义应该是这样的

 void f(std::string value)
 {
    // do something.
 }

如果你声明其他类如AdvString来实现操作符+ for intergers。如果你声明你的函数如下代码。它将像这个实现f(some_str + i);

一样工作
 void f(AdvString value)
 {
   // do something.
 }

示例实现在https://github.com/prasaathviki/advstring