我正在尝试开始一个有关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);
  }
}

最佳答案

您确定AV在clang_getSpellingLocation()而不是clang_getDiagnosticSpelling()上吗?

当使用__cdecl调用约定时,当结构的大小小于等于8字节时,允许不同厂商的编译器根据值返回结构。对于clang_getDiagnosticSpelling(),在32位环境中,CXString是8个字节。某些编译器(例如Visual C ++)直接在EAX:EDX CPU寄存器中返回8字节结构的内容,而其他编译器(例如C ++ Builder)使用隐藏的输出参数,该参数将引用传递给temp结构。

clang_getDiagnosticSpelling()(和其他类似函数)使用CXString返回EAX:EDX,但C ++ Builder使用隐藏参数代替。有一个简单的解决方法。 C ++ Builder期望__cdecl函数使用__int64返回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()的反汇编(我已经看到了返回CXString的函数的反汇编,这就是我肯定知道clang为此使用EAX:EDX的方式)。

关于c++ - libclang clang_getSpellingLocation访问冲突,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22113717/

10-16 06:20