2017-04-19 62 views
2

我的C++頭是C包裝爲C++類返回不正確的地址

header.hh

#include <stdint.h> 
#include <stdio.h> 
#ifdef __cplusplus 
#include <string> 
class A 
{ 
    uint32_t a; 
    public: 
     A(){ 
      a = 0; 
     } 
     void update(uint32_t b) { 
      a = b; 
     } 
}; 
#else 
typedef struct A A; 
#endif //__cplusplus 
#ifdef __cplusplus 
extern "C" { 
    void* newA(void); 
    void deleteA(A* a); 
    void update(A*a,uint32_t b); 
} 
#endif 

而我的C++文件是

class.cc

#include "header.hh" 
#include <iostream> 
extern "C" { 
    void* newA(void) { 
     A* a = new A(); 
     return (reinterpret_cast <void*> (a)); 
    } 
    void deleteA(A* a) { 
     delete a; 
    } 
    void update(A* a,uint32_t b){ 
     a->update(b); 
    } 
} 

main.c中

#include "header.hh" 
#include <stdio.h> 
int main() 
{ 
    A* a = (A*) newA(); 
    deleteA(a); 
} 

的Makefile

CFLAGS=-Wall -g -ansi -pedantic -std=c99 
CCFLAGS=-Wall -g 
LDFLAGS=-g -Wall -lstdc++ 

OBJS=class.o main.o 
PROG=test 

all:$(PROG) 
default: all 

%.o: %.cc 
    $(CC) $(CCFLAGS) -c $< 

%.o: %.c 
    $(CC) $(CFLAGS) -c $< 

$(PROG): $(OBJS) 
    $(CC) $(OBJS) $(LDFLAGS) -o [email protected] 

clean: 
    rm -rf $(OBJS) 
    rm -rf $(PROF) 

當我編譯並運行這個程序,我看到了段錯誤,當我嘗試調用主析構函數。

我走進GDB,發現地址「一」在class.cc是0x7fff980097a0並在主要是0xffffffff980097a0

什麼導致地址被改變?

我在ubuntu 14.04上使用gcc的4.8.4版本。

+0

順便說一句,你可能會返回'A的*'代替'無效*'爲'newA'。 – Jarod42

回答

5

當你編譯的main.c與C編譯器,它不會爲newAdeleteAupdate函數的聲明(他們與#ifdef __cplusplus包圍)。

所以,它會假設默認的簽名int newA()(其他兩個類似)。

這意味着,在這行:

A* a = (A*) newA(); 

newA()返回的值被視爲int,然後澆鑄到A*。將int轉換爲指針類型的結果是實現定義的。在你的平臺上,看起來你的行爲就是你觀察到的。

最有可能的是,在您的平臺上,sizeof(int)4,而sizeof(void*)8。在這種情況下,當作爲處理int0x7fff980097a0被截斷爲0x980097a0,然後澆鑄到A*當擴展到0xffffffff980097a0。這正是你所觀察到的。

相反,嘗試本作的聲明可見的C編譯器:

#ifdef __cplusplus 
extern "C" { 
#endif 
    void* newA(void); 
    void deleteA(A* a); 
    void update(A*a,uint32_t b); 
#ifdef __cplusplus 
} 
#endif 
+0

好的,那麼我該如何解決這個問題? – Tchinmai

+0

'main.c'如何編譯? –

+0

@Tchinmai:更新了我的答案以包含解決方案。 –

1

在標題:

#ifdef __cplusplus 
extern "C" { 
#endif 

// The header declaration is included both by the the C and the C++ 
// compiler. 

void* newA(void); 
void deleteA(A* a); 
void update(A*a,uint32_t b); 

#ifdef __cplusplus 
} 
#endif