预处理器定义在发布模式下工作,而不是调试
Preprocessor definitions work in Release mode, not Debug
我正在尝试在一个源文件 hw_model.cpp 中定义预处理器宏,而在另一个 main.cpp.
中保留它未定义
当我 运行 这个程序在 x64 发布模式下 (Visual Studio 2017) 时,一切都很好。当我在 x64 调试模式下 运行 时,main.cpp 中的 #undef ACT_LIKE_HARDWARE 语句似乎被忽略了。
model.h:
extern Signal signal;
void setSignalsFromHw();
// code below is inside some function :
#ifdef ACT_LIKE_HARDWARE
// perform a procedure that behaves like hardware
// This C code is supposed to act like hardware
// hardware has the freedom to write to read-only variables
#else
// perform some other procedure that firmware can normally do
#endif
main.cpp:
#undef ACT_LIKE_HARDWARE
#include "model.h"
Signals signal;
int main(){
uint32_t read_data = signal.wv0;
// do some processing on the read_data
setSignalsFromHw();
}
hw_model.cpp:
#define ACT_LIKE_HARDWARE
#include "macro.h"
// Perform a cast on the "signal" global variable
// This cast operation is done so that "signal_HWModel" has the freedom to write to read-only fields
Signals_HWModel* signal_HWModel = reinterpret_cast<Signals*>(&signal);
void setSignalsFromHw(){
ntfySignal_HWModel->wv0 = 0x2;
ntfySignal_HWModel->wv1 = 0x4;
}
首先,我是否应该在某些源文件中定义预处理器宏,而在其他文件中取消定义它?如果没有,什么是好的解决方法?请考虑 model.h 比我在这里所描述的要复杂得多,并且重构起来有些困难,但我绝对愿意接受所有建议。
其次,为什么 运行ning 在调试模式和发布模式之间有区别?
谢谢
---------------- **更新** --------------
根据要求,这是最小的,运行可用代码。它说明了我在上面遇到的相同问题。抱歉,如果它看起来与上面的略有不同。我只是小心不要透露太多 IP。
重要提示:我正在使用 Google 测试框架,以及它们提供的 main() 函数。在 Release 中,我得到了预期的行为(undef 语句有效并且 define 语句有效)。在调试中,其中一个预处理器语句不会被命中。
test.cpp
#undef ACT_LIKE_HW
#include "gtest/gtest.h"
#include "model.h"
TEST(TestCaseName, TestName) {
setSignalsFromHW();
Block::assignSig();
}
hw_model.cpp
#define ACT_LIKE_HW
#include "model.h"
void setSignalsFromHW() {
Block::assignSig();
}
model.h
#pragma once
#include <iostream>
using namespace std;
void setSignalsFromHW();
class Block {
public:
static void assignSig() {
#ifdef ACT_LIKE_HW
cout << "Performing hardware operations" << endl;
#else
cout << "Procedures that firmware usually executes" << endl;
#endif
}
};
但是,如果我创建一个全新的 C++ 项目(不使用 Google 测试,因此它是一个常规的控制台应用程序),其中一个预处理器语句不会同时用于 Release 和 Debug ,所以这违背了我定义这 2 个预处理器语句的目的。我可能最终会重构代码,但我仍然想知道为什么我的 Google 测试项目会出现这个问题。
您违反了单一定义规则。
如果您在一个程序中对同一个符号有多个定义,那么如果两个定义不相同,您的程序就会出现未定义的行为。
通常,链接器会删除重复的符号,因此只有一个函数会保留下来,并且两个调用站点最终都会调用相同的函数。
如果函数被编译器内联,则函数中的代码会集成到调用函数中,链接器不会干扰,因此您的代码可能会正常工作。这很脆弱,因为当调试中没有发生内联时,或者当您的函数增长超过编译器内联它的大小阈值时,您将再次回到只有一个函数的状态。
要修复它,请将一个布尔参数传递给控制您想要的行为的函数。如果此函数是内联的,编译器应删除未使用的代码分支。
或者使布尔参数成为模板参数并使用if constexpr
,这将保证删除未使用的代码。
我正在尝试在一个源文件 hw_model.cpp 中定义预处理器宏,而在另一个 main.cpp.
中保留它未定义当我 运行 这个程序在 x64 发布模式下 (Visual Studio 2017) 时,一切都很好。当我在 x64 调试模式下 运行 时,main.cpp 中的 #undef ACT_LIKE_HARDWARE 语句似乎被忽略了。
model.h:
extern Signal signal;
void setSignalsFromHw();
// code below is inside some function :
#ifdef ACT_LIKE_HARDWARE
// perform a procedure that behaves like hardware
// This C code is supposed to act like hardware
// hardware has the freedom to write to read-only variables
#else
// perform some other procedure that firmware can normally do
#endif
main.cpp:
#undef ACT_LIKE_HARDWARE
#include "model.h"
Signals signal;
int main(){
uint32_t read_data = signal.wv0;
// do some processing on the read_data
setSignalsFromHw();
}
hw_model.cpp:
#define ACT_LIKE_HARDWARE
#include "macro.h"
// Perform a cast on the "signal" global variable
// This cast operation is done so that "signal_HWModel" has the freedom to write to read-only fields
Signals_HWModel* signal_HWModel = reinterpret_cast<Signals*>(&signal);
void setSignalsFromHw(){
ntfySignal_HWModel->wv0 = 0x2;
ntfySignal_HWModel->wv1 = 0x4;
}
首先,我是否应该在某些源文件中定义预处理器宏,而在其他文件中取消定义它?如果没有,什么是好的解决方法?请考虑 model.h 比我在这里所描述的要复杂得多,并且重构起来有些困难,但我绝对愿意接受所有建议。
其次,为什么 运行ning 在调试模式和发布模式之间有区别?
谢谢
---------------- **更新** --------------
根据要求,这是最小的,运行可用代码。它说明了我在上面遇到的相同问题。抱歉,如果它看起来与上面的略有不同。我只是小心不要透露太多 IP。
重要提示:我正在使用 Google 测试框架,以及它们提供的 main() 函数。在 Release 中,我得到了预期的行为(undef 语句有效并且 define 语句有效)。在调试中,其中一个预处理器语句不会被命中。
test.cpp
#undef ACT_LIKE_HW
#include "gtest/gtest.h"
#include "model.h"
TEST(TestCaseName, TestName) {
setSignalsFromHW();
Block::assignSig();
}
hw_model.cpp
#define ACT_LIKE_HW
#include "model.h"
void setSignalsFromHW() {
Block::assignSig();
}
model.h
#pragma once
#include <iostream>
using namespace std;
void setSignalsFromHW();
class Block {
public:
static void assignSig() {
#ifdef ACT_LIKE_HW
cout << "Performing hardware operations" << endl;
#else
cout << "Procedures that firmware usually executes" << endl;
#endif
}
};
但是,如果我创建一个全新的 C++ 项目(不使用 Google 测试,因此它是一个常规的控制台应用程序),其中一个预处理器语句不会同时用于 Release 和 Debug ,所以这违背了我定义这 2 个预处理器语句的目的。我可能最终会重构代码,但我仍然想知道为什么我的 Google 测试项目会出现这个问题。
您违反了单一定义规则。
如果您在一个程序中对同一个符号有多个定义,那么如果两个定义不相同,您的程序就会出现未定义的行为。
通常,链接器会删除重复的符号,因此只有一个函数会保留下来,并且两个调用站点最终都会调用相同的函数。
如果函数被编译器内联,则函数中的代码会集成到调用函数中,链接器不会干扰,因此您的代码可能会正常工作。这很脆弱,因为当调试中没有发生内联时,或者当您的函数增长超过编译器内联它的大小阈值时,您将再次回到只有一个函数的状态。
要修复它,请将一个布尔参数传递给控制您想要的行为的函数。如果此函数是内联的,编译器应删除未使用的代码分支。
或者使布尔参数成为模板参数并使用if constexpr
,这将保证删除未使用的代码。