0

我正在尝试开始编写有关 libclang 库的教程,但在调用该函数时出现访问冲突clang_getSpellingLocation()。有关错误的其他信息通过错误计数、行和列正确报告。

我的环境:C++Builder XE pro、Windows 7 32bit、LLVM 3.4、libCLang.lib 使用 coff2omf、libCLang.dll 转换。

我在 Visual C++ 2010 上测试了相同的代码,它工作正常。

请问有人可以帮我解决这个问题吗?

我的简单代码

//---------------------------------------------------------------------------
void __fastcall TForm8::Button1Click(TObject *Sender)
{

    unsigned line, column;
    CXIndex index = clang_createIndex(0, 0);

    const  char  * args []  =  {
    "-I/usr/include" ,
    "-I."
    };

    int  numArgs  =  sizeof ( args )  /  sizeof ( * args );

  CXTranslationUnit tu = clang_parseTranslationUnit(index, "G:\\projects\\LibCLang  \\File2.cpp", args, numArgs, NULL, 0, CXTranslationUnit_None);

  unsigned  diagnosticCount  =  clang_getNumDiagnostics ( tu );

  for ( unsigned  i  =  0 ;  i  <  diagnosticCount ;  i++ )
  {
      CXDiagnostic  diagnostic   =  clang_getDiagnostic ( tu ,  i );
      CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
      clang_getSpellingLocation(location, NULL, &line, &column, NULL);
      CXString text = clang_getDiagnosticSpelling(diagnostic);
      UnicodeString s = clang_getCString(text);
  }
}
4

1 回答 1

2

你确定 AV 是开clang_getSpellingLocation()还是不开clang_getDiagnosticSpelling()

当使用__cdecl调用约定时,当结构的大小 <= 8 字节时,允许不同供应商的编译器在按值返回结构时做任何他们想做的事情。在 的情况下clang_getDiagnosticSpelling()CXString在 32 位环境中是 8 个字节。一些编译器,如 Visual C++,直接在 CPU 寄存器中返回一个 8 字节结构的内容EAX:EDX,而其他编译器,如 C++Builder,使用一个隐藏的输出参数来传递对临时结构的引用。

clang_getDiagnosticSpelling()(和其他类似函数)返回CXStringusing EAX:EDX,但 C++Builder 使用隐藏参数。有一个简单的解决方法。C++Builder 期望__cdecl函数返回__int64using EAX:EDX,并且由于CXString__int64在 32 位中的大小相同,您可以执行以下操作:

typedef __int64 __cdecl (*clang_getDiagnosticSpellingHack)(CXDiagnostic);

//CXString text = clang_getDiagnosticSpelling(diagnostic);
clang_getDiagnosticSpellingHack func = reinterpret_cast<clang_getDiagnosticSpellingHack>(&clang_getDiagnosticSpelling);
__int64 tmp = func(diagnostic);
CXString text = reinterpret_cast<CXString&>(tmp);

或者,您可以利用 C++Builder_EAX_EDX内在函数:

typedef void __cdecl (*clang_getDiagnosticSpellingHack)(CXDiagnostic);

//CXString text = clang_getDiagnosticSpelling(diagnostic);
clang_getDiagnosticSpellingHack func = reinterpret_cast<clang_getDiagnosticSpellingHack>(&clang_getDiagnosticSpelling);
CXString text;
func(diagnostic);
text.ptr_data = (void*) _EAX;
text.int_data = _EDX;

至于clang_getSpellingLocation(),我不希望在约定中有这样的不匹配,因为它没有返回值,除非clang_getSpellingLocation()被编译为接受它的CXSourceLocation参数与 C++Builder 传递它的方式不同。C++Builder 将所有三个数据值CXSourceLocation直接从调用堆栈中压入。您必须查看反汇编clang_getSpellingLocation()以了解它实际上是如何访问其CXSourceLocation参数的值,然后根据需要相应地调整您的 C++Builder 代码。

您还应该仔细检查如何clang_getDiagnosticLocation()返回它CXSourceLocation,以确保它与 C++Builder 期望它返回的方式相匹配(通过引用的隐藏输出参数),以确保clang_getSpellingLocation()在调用之前内存没有被破坏。因此,它clang_getSpellingLocation()本身可能不是罪魁祸首。很难说没有看到和的反汇编clang_getDiagnosticLocation()clang_getSpellingLocation()我已经看到了 return 函数的反汇编CXString,这就是我确定 clangEAX:EDX用于此的方法)。

于 2014-03-07T22:43:20.560 回答