【问题标题】:C++ #define value not defined in source fileC++ #define 值未在源文件中定义
【发布时间】:2021-01-09 15:28:49
【问题描述】:

我在我的主文件中定义一个值,然后包含一个头文件。定义的值未在源文件中定义。

Main.cpp:

#define TN_VALUE double
#include "SomeFile.hpp"

int main()
{
  TN_VALUE x = 3;
  func(x);
  return 0;
}

SomeFile.hpp:

#ifndef _SOME_FILE
#define _SOME_FILE
#ifndef TN_VALUE
#define TN_VALUE float
#endif
void func(TN_VALUE); // TN_VALUE = double
#endif

SomeFile.cpp:

#include "SomeFile.hpp"
#include <iostream>

void func(TN_VALUE _value) // TN_VALUE = float
{
  std::cout << _value << std::endl;
}

【问题讨论】:

  • 在这两种情况下都有定义。我不确定你到底在问什么。你在问为什么它在一个文件中是double 而在另一个文件中是float
  • 是什么让您认为它没有定义?你有两个TN_VALUE 的#define 语句,一个是double,一个是float。你到底为什么要这样做?
  • 这并没有解决问题,但以下划线开头的名称后跟大写字母 (_SOME_FILE) 和包含两个连续下划线的名称保留供实现使用。不要在你的代码中使用它们。

标签: c++ visual-c++ c-preprocessor


【解决方案1】:

我假设你的问题是,
为什么TN_VALUEMain.cpp 中是double 而在SomeFile.cpp 中是float

对于那个问题,这就是解释,
在 C++ 中,当你包含一个头文件时,它的内容会被复制到源文件中。这意味着Main.cpp 文件中将有一个SomeFile.hpp 文件的副本,而SomeFile.cpp 文件中将有另一个副本。所以现在当编译器运行源文件时,在一个文件中TN_VALUE的定义是float(在SomeFile.cpp中),它的值是double(因为你已经明确定义了它)在另一个文件中( Main.cpp)。
这意味着将有两个不同的(重载)函数。一个是void func(float),另一个是void func(double)

由于函数定义存在于 SomeFile.cpp 文件中,它可以毫无问题地编译,但 Main.cpp 文件会出现问题,因为编译器说有一个签名为 void func(double) 的函数链接器找不到(因为没有编译这样的函数)。这将触发链接错误。

要解决此问题,您可以在头文件本身中定义函数并完全放弃 SomeFile.cpp 文件。这样,函数定义将放在Main.cpp 文件中,TN_VALUE 的定义将解析为double。之后此函数不会出现链接错误。

【讨论】:

    【解决方案2】:

    我们可以使用g++-E 标志来调查预处理代码的样子:

    在预处理阶段后停止;不要正确运行编译器。输出是经过预处理的源代码形式,发送到标准输出。

    (source)

    这是Main.cpp的预处理代码:

    $ g++ -E Main.cpp 
    # 1 "Main.cpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "Main.cpp"
    
    # 1 "SomeFile.hpp" 1
    
    
    
    
    
    void func(double);
    # 3 "Main.cpp" 2
    
    int main()
    {
      double x = 3;
      func(x);
      return 0;
    }
    

    如果我们删除#include &lt;iostream&gt;,这里是SomeFile.cpp 的预处理代码:

    $ g++ -E SomeFile.cpp
    # 1 "SomeFile.cpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "SomeFile.cpp"
    # 1 "SomeFile.hpp" 1
    
    
    
    
    
    void func(float);
    # 2 "SomeFile.cpp" 2
    
    
    void func(float _value)
    {
      std::cout << _value << std::endl;
    }
    

    我们可以看到,在Main.cppTN_VALUEdouble,因此我们得到void func(double);double x = 3;。在SomeFile.cpp 中,TN_VALUEfloat。这是为什么呢?

    这一切都与

    有关
    #ifndef TN_VALUE
    #define TN_VALUE float
    #endif
    

    SomeFile.hpp。这告诉预处理器,如果未定义TN_VALUE,则将TN_VALUE 设置为float。如果定义了TN_VALUE,则什么也不做(留下TN_VALUE 的值。

    Main.cpp,你有

    #define TN_VALUE double
    #include "SomeFile.hpp"
    

    这里的顺序意味着TN_VALUE将在预处理器到达SomeFile.hpp中的ifndef之前定义,因此TN_VALUE将保留double的值。

    然后在SomeFile.cpp 中,您立即拥有#include "SomeFile.hpp"。由于SomeFile.cpp 是独立于Main.cpp 的翻译单元,因此未定义TN_VALUE。这意味着,由于在预处理器到达SomeFile.hpp 中的ifndef 时未设置TN_VALUE,因此预处理器将到达#define TN_VALUE float 行,这将导致它将TN_VALUE 设置为float

    更多g++ -E分析

    如果这是一个更大、更复杂的代码库,我们可能希望通过查看 SomeFile.hpp 和使用不同定义生成的预处理输出来更仔细地隔离问题。

    我们可以查看SomeFile.hpp 的预处理输出,没有定义:

    $ g++ -E SomeFile.hpp
    # 1 "SomeFile.hpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "SomeFile.hpp"
    
    
    
    
    
    void func(float);
    

    我们也可以使用g++-D 标志来进行定义。如果我们使用-D TN_VALUE=double,我们应该会看到与Main.cpp 匹配的内容:

    $ g++ -D TN_VALUE=double -E SomeFile.hpp
    # 1 "SomeFile.hpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "SomeFile.hpp"
    
    
    
    
    
    void func(double);
    

    我们已经从上面的分析中预料到了这些结果。但是,这表明我们可以根据不同定义的各种值来测试任何 C 或 C++ 头文件生成的预处理代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-11
      相关资源
      最近更新 更多