【问题标题】:Invoking function with string argument with lldb: how?使用 lldb 调用带有字符串参数的函数:如何?
【发布时间】:2014-07-29 01:55:59
【问题描述】:

我无法使用 lldb 调用带有字符串参数的简单、非模板化函数。有什么方法可以让 lldb 理解 C++ 数据类型“字符串”,这是 C++ 程序中常用的数据类型?

这里的示例源代码只是创建了一个带有几个构造函数的简单类,然后调用它们(包括“iostream”和“string”省略):

using namespace std;

struct lldbtest{
  int bar=5;
  lldbtest(){bar=6;}
  lldbtest(int foo){bar=foo;}
  lldbtest(string fum){bar=7;}
};

int main(){
  string name="fum";
  lldbtest x,y(3);
  cout<<x.bar<<y.bar<<endl;
  return 0;
}

在 Mac Maverick 上编译时使用

g++ -g -std=c++11 -o testconstructor testconstructor.cpp

程序运行并打印“63”的预期输出。

但是,如果在 main 中的 return 语句之前设置了一个断点,并且尝试调用构造函数失败并显示一个神秘的错误消息:

p lldbtest(string("hey there"))
error: call to a function              'lldbtest::lldbtest(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)' ('_ZN8lldbtestC1ENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE') that is not present in the target
error: The expression could not be prepared to run in the target

可能也相关,命令:

 p lldbtest(name)

什么都不打印。

另外,使用字符串字面量调用构造函数也失败了,标准方式:

p lldbtest("foo")

给出类似的长错误:

 error: call to a function 
'lldbtest::lldbtest(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)' ('_ZN8lldbtestC1ENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE') that is not present in the targeterror: The expression could not be prepared to run in the target

有什么方法可以让 lldb 理解和使用 C++“字符串”数据类型?我有许多采用字符串参数的函数,并且需要一种从调试器调用这些函数的方法。在 Mac 上。

【问题讨论】:

    标签: c++ string c++11 lldb


    【解决方案1】:

    问题

    这是由于您的代码存在一个微妙的问题,归结为 C++ 标准中的以下措辞:

    7.1.2p3-4 函数说明符 [dcl.fct.spec]

    在类定义中定义的函数是内联函数。

    ...

    内联函数应在使用 odr 的每个翻译单元中定义,并且在每种情况下都应具有完全相同的定义 (3.2)。

    您的构造函数lldbtest(std::string)lldbtest 的主体中定义,这意味着它将隐式内联,这进一步意味着编译器不会为它生成任何代码,除非它用于翻译单元

    由于定义必须存在于每个可能调用它的翻译单元中,我们可以想象编译器会说; “哎呀,我不需要这样做..如果其他人使用它,他们将生成代码”。

    lldb 将寻找一个不存在的函数定义,因为gcc 没有生成一个;因为你没用过。


    解决方案

    如果我们将lldbtest 的定义更改为以下内容,我敢打赌它会按您的预期工作:

    struct lldbtest{
      int bar=5;
      lldbtest();
      lldbtest(int foo);
      lldbtest(string fum);
    };
    
    lldbtest::lldbtest() { bar=6; }
    lldbtest::lldbtest(int) { bar=7; }
    lldbtest::lldbtest(string) { bar=8; }
    

    但是.. p lldbtest(name) 呢?

    lldb 中的命令p 用于print* 信息,但也可用于评估表达式

    lldbtest(name) 不会使用名为 name 的变量调用 lldbtest 的构造函数,它相当于声明一个名为 name 的变量lldbtest 类型; IE。 lldbtest name 在语义上是等价的。

    【讨论】:

    • 很好的答案,感谢您提供的信息。确实,您是对的:按照您的建议更改功能可以解决问题。
    • 在实际代码中,构造函数是在类外部定义的。只是,真正的代码有很多文件和很多类,很难作为一个例子来呈现。但在实际代码中,我在某个时候停止了调试器,并尝试使用字符串参数调用构造函数,但失败了。你知道为什么会这样吗?我似乎无法重现一个小例子。顺便说一句,你如何从 lldb 调用 lldbtest(name)?
    • @kdog 标准规定(lidbtest)(name) 不能被解释为声明,因此p (libdtest)(name) 将创建一个用name 初始化的临时libdtest。没有看到真实的代码,没有办法知道,但是真实的代码可能是使用类模板吗?
    • 我已经能够用两个小文件重现这个问题,我将在另一个问题中发布,因为你完美地回答了这个问题。不,这个特定的函数没有使用模板——当然,除了间接通过“字符串”,它是一个模板。
    • @kdog 在您发布问题后告诉我,我会尝试就此事提供一些见解。
    【解决方案2】:

    将在此处回答所提出的问题,而不是使用操作代码解决问题。特别是因为这花了我一段时间才弄清楚。

    Use a string in a function invocation in lldb in C++

    (这篇文章帮助很大,值得一读:Dancing in The Debugger

    【讨论】:

      猜你喜欢
      • 2014-07-29
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-25
      • 2010-12-19
      相关资源
      最近更新 更多