2012-10-12 143 views
3

也許這是回答那裏的地方,我只是不知道要搜索它的話。我試圖瞭解我是否看到錯誤,或者如果我不瞭解減號運算符。在標題中分配常量會導致編譯器跳過' - '?未定義的引用 - 應該在C++中的`a = -b;`和`a = -1 * b;`和`a = 0-b'之間有區別嗎?

我的項目具有以下結構,包括生成的文件:

 
test 
├── src 
│   ├── TipCoordinate.cpp 
│   └── TipCoordinate.hpp 
└── UnitTest 
    ├── main.cpp 
    ├── main.o 
    ├── Makefile 
    ├── TipCoordinate.o 
    ├── UnitTest.pro 
    └── UnitTest.pro.user 

我已經在我的課標頭中定義的常量如下:

class TipCoordinate{ 
public: 
    TipCoordinate() {}; 
    ~TipCoordinate() {}; 
    void Z(const float z); 
private: 
    static const float sREFERENCE_SPHERE_RADIUS = 12; 
}; 

在我班上的cpp文件將下面的代碼不能編譯:

#include "TipCoordinate.hpp" 
void TipCoordinate::Z(const float z){ 
    float z_origin_ = -sREFERENCE_SPHERE_RADIUS; 
} 

我收到錯誤.../model/TipCoordinate.cpp:143: error: undefined reference to 'TipCoordinate::sREFERENCE_SPHERE_RADIUS'

但是,如果我只是改變它,然後跟隨它是完全幸福:

#include "TipCoordinate.hpp" 
void TipCoordinate::Z(const float z){ 
    float z_origin_ = -1*sREFERENCE_SPHERE_RADIUS; 
} 

另外,該作品也:

#include "TipCoordinate.hpp" 
void TipCoordinate::Z(const float z){ 
    float z_origin_ = 0-sREFERENCE_SPHERE_RADIUS; 
} 

我認爲亞當羅森菲爾德的回答解決了我的問題,但作爲對一些評論的迴應,我用一個重現問題的最小,完整的例子取代了上述摘錄。正如一些推測,我使用g ++。版本是g ++(Ubuntu/Linaro 4.5.2-8ubuntu4)4.5.2,並且優化器似乎可能會受到影響,因爲我使用的是「基於Qt 4.7.2(32位)的Qt Creator 2.1.0」,構建於2011年3月11日「。這裏是我的項目文件:

QT  -= gui 
INCLUDEPATH += ../src 
TEMPLATE = app 
SOURCES += main.cpp \ 
    ../src/TipCoordinate.cpp 
HEADERS += \ 
    ../src/TipCoordinate.hpp 

我的主要文件只是以下,但改變的項目模板庫和消除主文件導致該問題消失。

int main() { return 0; } 

我懷疑,Qt Creator中很重要,因爲除了更改模板,當我改變其他看似風馬牛不相及的因素問題消失或再次出現。出於這個原因,我已經包括了Qt Creator中產生的Makefile如下:

############################################################################# 
# Makefile for building: UnitTest 
# Generated by qmake (2.01a) (Qt 4.7.3) on: Sun Oct 14 15:05:23 2012 
# Project: UnitTest.pro 
# Template: app 
# Command: /usr/local/Trolltech/QtEmbedded-4.7.3/bin/qmake -spec /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qws/linux-x86-g++ CONFIG+=debug QMLJSDEBUGGER_PATH=/usr/share/qtcreator/qml/qmljsdebugger -o Makefile UnitTest.pro 
############################################################################# 

####### Compiler, tools and options 

CC   = gcc 
CXX   = g++ 
DEFINES  = -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED 
CFLAGS  = -pipe -g -Wall -W -D_REENTRANT $(DEFINES) 
CXXFLAGS  = -pipe -g -Wall -W -D_REENTRANT $(DEFINES) 
INCPATH  = -I/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qws/linux-x86-g++ -I. -I/usr/local/Trolltech/QtEmbedded-4.7.3/include/QtCore -I/usr/local/Trolltech/QtEmbedded-4.7.3/include/QtNetwork -I/usr/local/Trolltech/QtEmbedded-4.7.3/include -I../src -I. 
LINK   = g++ 
LFLAGS  = -Wl,-rpath,/usr/local/Trolltech/QtEmbedded-4.7.3/lib 
LIBS   = $(SUBLIBS) -L/usr/local/Trolltech/QtEmbedded-4.7.3/lib -lQtNetwork -L/usr/local/Trolltech/QtEmbedded-4.7.3/lib -lQtCore -lpthread 
AR   = ar cqs 
RANLIB  = 
QMAKE   = /usr/local/Trolltech/QtEmbedded-4.7.3/bin/qmake 
TAR   = tar -cf 
COMPRESS  = gzip -9f 
COPY   = cp -f 
SED   = sed 
COPY_FILE  = $(COPY) 
COPY_DIR  = $(COPY) -r 
STRIP   = strip 
INSTALL_FILE = install -m 644 -p 
INSTALL_DIR = $(COPY_DIR) 
INSTALL_PROGRAM = install -m 755 -p 
DEL_FILE  = rm -f 
SYMLINK  = ln -f -s 
DEL_DIR  = rmdir 
MOVE   = mv -f 
CHK_DIR_EXISTS= test -d 
MKDIR   = mkdir -p 

####### Output directory 

OBJECTS_DIR = ./ 

####### Files 

SOURCES  = main.cpp \ 
     ../src/TipCoordinate.cpp 
OBJECTS  = main.o \ 
     TipCoordinate.o 
DIST   = /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/g++.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/unix.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/linux.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/qws.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qconfig.pri \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/modules/qt_webkit_version.pri \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_functions.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_config.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/exclusive_builds.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_pre.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/debug.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_post.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/warn_on.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/unix/thread.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/moc.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/resources.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/uic.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/yacc.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/lex.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/include_source_dir.prf \ 
     UnitTest.pro 
QMAKE_TARGET = UnitTest 
DESTDIR  = 
TARGET  = UnitTest 

first: all 
####### Implicit rules 

.SUFFIXES: .o .c .cpp .cc .cxx .C 

.cpp.o: 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "[email protected]" "$<" 

.cc.o: 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "[email protected]" "$<" 

.cxx.o: 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "[email protected]" "$<" 

.C.o: 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "[email protected]" "$<" 

.c.o: 
    $(CC) -c $(CFLAGS) $(INCPATH) -o "[email protected]" "$<" 

####### Build rules 

all: Makefile $(TARGET) 

$(TARGET): $(OBJECTS) 
    $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) 

Makefile: UnitTest.pro /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qws/linux-x86-g++/qmake.conf /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/g++.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/unix.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/linux.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/qws.conf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qconfig.pri \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/modules/qt_webkit_version.pri \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_functions.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_config.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/exclusive_builds.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_pre.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/debug.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_post.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/warn_on.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/unix/thread.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/moc.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/resources.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/uic.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/yacc.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/lex.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/include_source_dir.prf \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/lib/libQtNetwork.prl \ 
     /usr/local/Trolltech/QtEmbedded-4.7.3/lib/libQtCore.prl 
    $(QMAKE) -spec /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qws/linux-x86-g++ CONFIG+=debug QMLJSDEBUGGER_PATH=/usr/share/qtcreator/qml/qmljsdebugger -o Makefile UnitTest.pro 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/g++.conf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/unix.conf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/linux.conf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/common/qws.conf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qconfig.pri: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/modules/qt_webkit_version.pri: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_functions.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt_config.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/exclusive_builds.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_pre.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/debug.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/default_post.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/warn_on.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/qt.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/unix/thread.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/moc.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/resources.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/uic.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/yacc.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/lex.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/features/include_source_dir.prf: 
/usr/local/Trolltech/QtEmbedded-4.7.3/lib/libQtNetwork.prl: 
/usr/local/Trolltech/QtEmbedded-4.7.3/lib/libQtCore.prl: 
qmake: FORCE 
    @$(QMAKE) -spec /usr/local/Trolltech/QtEmbedded-4.7.3/mkspecs/qws/linux-x86-g++ CONFIG+=debug QMLJSDEBUGGER_PATH=/usr/share/qtcreator/qml/qmljsdebugger -o Makefile UnitTest.pro 

dist: 
    @$(CHK_DIR_EXISTS) .tmp/UnitTest1.0.0 || $(MKDIR) .tmp/UnitTest1.0.0 
    $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/UnitTest1.0.0/ && $(COPY_FILE) --parents ../src/TipCoordinate.hpp .tmp/UnitTest1.0.0/ && $(COPY_FILE) --parents main.cpp ../src/TipCoordinate.cpp .tmp/UnitTest1.0.0/ && (cd `dirname .tmp/UnitTest1.0.0` && $(TAR) UnitTest1.0.0.tar UnitTest1.0.0 && $(COMPRESS) UnitTest1.0.0.tar) && $(MOVE) `dirname .tmp/UnitTest1.0.0`/UnitTest1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/UnitTest1.0.0 


clean:compiler_clean 
    -$(DEL_FILE) $(OBJECTS) 
    -$(DEL_FILE) *~ core *.core 


####### Sub-libraries 

distclean: clean 
    -$(DEL_FILE) $(TARGET) 
    -$(DEL_FILE) Makefile 


check: first 

mocclean: compiler_moc_header_clean compiler_moc_source_clean 

mocables: compiler_moc_header_make_all compiler_moc_source_make_all 

compiler_moc_header_make_all: 
compiler_moc_header_clean: 
compiler_rcc_make_all: 
compiler_rcc_clean: 
compiler_image_collection_make_all: qmake_image_collection.cpp 
compiler_image_collection_clean: 
    -$(DEL_FILE) qmake_image_collection.cpp 
compiler_moc_source_make_all: 
compiler_moc_source_clean: 
compiler_uic_make_all: 
compiler_uic_clean: 
compiler_yacc_decl_make_all: 
compiler_yacc_decl_clean: 
compiler_yacc_impl_make_all: 
compiler_yacc_impl_clean: 
compiler_lex_make_all: 
compiler_lex_clean: 
compiler_clean: 

####### Compile 

main.o: main.cpp 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp 

TipCoordinate.o: ../src/TipCoordinate.cpp ../src/TipCoordinate.hpp 
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o TipCoordinate.o ../src/TipCoordinate.cpp 

####### Install 

install: FORCE 

uninstall: FORCE 

FORCE: 

我看到一個滾動框出現,但如果有一種方法,使顯示更簡潔,我歡迎任何提示。

+5

這是什麼編譯器?聽起來像一個錯誤。 –

+0

當我解決UVa上的編程問題時,我面臨同樣的問題。我在使用'abs'函數時遇到了錯誤的答案,但是當創建我自己的'abs'時,它已被接受! – 2012-10-12 20:51:12

+0

我最好的猜測是,你沒有向我們展示一些小的變化。你能向我們展示一個展示錯誤的簡短自包含程序嗎? http://sscce.org/ –

回答

5

您看到的行爲差異在於優化程序。無論出於何種原因,優化器都會決定優化數學運算,並在某些情況下用浮點常量代替它,但不是全部情況。當它這樣做時,不會發生錯誤,因爲變量sREFERENCE_SPHERE_RADIUS在任何地方都不會被引用。

什麼來發生的事情是,你應該是,讓在所有的情況下,「未定義的引用」錯誤,因爲sREFERENCE_SPHERE_RADIUS需要的變量被賦予類定義之外的明確定義。 C++標準只允許你給一個static類成員的初始化,如果它是整數或枚舉類型:

// Header file 
class TipCoordinate 
{ 
    static const float sREFERENCE_SPHERE_RADIUS; // declaration 
}; 

// Source file 
const float TipCoordinate::sREFERENCE_SPHERE_RADIUS = 12; // definition 

從C++ 03第9.2節/ 4:

A member-declarator can contain a constant-initializer only if it declares a static member (9.4) of const integral or const enumeration type, see 9.4.2.

在最新版本的C++語言,C++ 11,規則稍微寬鬆一些,您可以在聲明中定義浮點常量,但必須使用constexpr而不是const

+0

在C++ 11中,您可以使用'constexpr'來允許進行類內初始化。 –

+0

我從以前的經驗中知道,將定義添加到源文件可以解決這個問題,但今天我驚訝地發現添加一點數學算法似乎也有效。 'static const float varname = XX.XXXX;'語法在我們團隊的頭文件中相當常見,我是一個經驗較少的團隊成員,所以我不會想到這個錯誤是編譯器期望的行爲。謝謝! – sage

1

(我不得不不少編輯這個答案由於嚴重thinko!所以,只是希望這並不能否定任何評論。)

假設你已經證明確實是所有存在的代碼(一個完成最小的例子會澄清的事情!),那麼它是一個編譯器的bug,它編譯!

你可以用各種方法解決它。

首先,因爲你有一個頭+實現文件,然後簡單地刪除了在類聲明的初始化,並在cpp文件添加此:

float const TipCoordinate::sREFERENCE_SPHERE_RADIUS = 12.0; 

注意的積分常數輸入你的即可在類內聲明中初始化它。此外,使用C++ 11,您可以使用constexpr來允許對類內聲明進行初始化。無論如何,類中的聲明在技術上是純聲明,而cpp文件中的聲明(如果有的話)是一個定義(即使沒有初始化器,可能是整型常量的情況)。

對於只有標頭的模塊,您可以改爲&hellip;

static double referenceSphereRadius() { return 12.0; } 

或例如&hellip;

template< class Dummy > 
class TipCoordinate_constants 
{ 
protected: 
    static double const referenceSphereRadius; 
}; 

template< class Dummy > 
double const TipCoordinate_constants<Dummy>::referenceSphereRadius = 12.0; 

class TipCoordinate 
    private TipCoordinate_constants<void> 
{ 
    // ... 
}; 

這些技術還可以在C++ 03編譯器中正常工作。

請注意不使用SHOUTING UPPERCASE。請保留宏名稱。 C++不是Java。

+0

大喊大寫符合我堅持的團隊編碼標準。這不是我的首選選擇,但在這種情況下,我認爲整個項目的價值均高於我的偏好。 – sage

相關問題