【问题标题】:C/C++ replacement/redefinition rules?C/C++ 替换/重定义规则?
【发布时间】:2009-04-18 04:01:06
【问题描述】:

我对 C/C++ 并不是特别陌生,但今天我发现了一些我没想到的东西。 这在 gcc 中编译:


/* test.c */
#include <stddef.h> // !

typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR

int
main(void)
{
  typedef unsigned long int size_t; // NO ERROR
  return 0;
}

这不是:


/* test.c */
#include <stddef.h>

typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR

int
main(void)
{
  typedef unsigned long int size_t; // NO ERROR
  typedef unsigned long int size_t; // ERROR
  return 0;
}

这也不是:


/* test.h */ // ! header
typedef unsigned long int size_t;
typedef unsigned long int size_t; // ERROR

类似地在 g++ 中编译:


/* test.h */ // ! header
#include <cstddef>

inline void* operator new(size_t, void* p) throw() { return p; }

这不是:


/* test.h */ // ! header
#include <new> // !

inline void* operator new(size_t, void* p) throw() { return p; } // ERROR

这样做:


/* test.cc */
#define _NEW

#include <new> // !
#include <iostream>
#include <cstdlib>

using std::cout;
using std::endl;

inline void* operator new(size_t size) throw() // NO ERROR EXPECTED
{
  cout << "OPERATOR NEW CALLED" << endl;
  return malloc(size);
}

inline void* operator new(size_t, void* p) throw() // NO ERROR
{
  cout << "PLACEMENT NEW CALLED" << endl;
  return p;
}

int main()
{
  char *buffer[4];
  int *i = new (buffer) int;
  int *j = new int;
  return 0;
}

(替换标准的 new 运算符在上述所有情况下都有效。替换替换的 new 运算符是非法的,我知道。)

很容易看到一种模式,但有人可以给我一个“标准”的解释吗? 为什么我可以在 .c 或 .cc 文件中做一些我在 .h 文件中做不到的事情(重新定义旧的 typedef,替换非法替换的函数)?


感谢您的回复。我省略了一些代码,包括标题保护。在最后一个 .cc 示例中,我将 HTML 编码为 的标头保护定义了 _NEW,所以我在这里定义它阻止了标准新标头的包含,所以我替换工作了

m@m:~/Desktop/Library$ ./a.out 安置新呼叫 操作员新呼叫

所以,是的,唯一无法解释的是我为什么可以多次在 .c/.cc 文件中重新键入定义内容,但不能像这样在 .h 中重新键入:

/* test.c */
#include <stddef.h>

typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR

int
main(void)
{
  typedef unsigned long int size_t; // NO ERROR
  return 0;
}

反正我也不想这样做,只是想知道。

编辑:谢谢,这真的回答了所有问题。将其更改为 xyz 不允许在给定范围内进行多个定义,这感觉不错。 :) 我进行这些小测试的原因是我正在为一个小型操作系统编写 C 和 C++ 的一个子集,但是由于我使用现有的库而没有删除任何东西来帮助我进行测试,所以我试图弄清楚了解如何确保 (1) 我的代码在测试中被调用(例如我的新位置)和 (2) 我的代码不会与 GNU 库发生冲突。 (1)的答案现在看起来很明显。我只是将标准 X.h 中的标头保护宏#define 到我的 X.h 中:)。

【问题讨论】:

  • 听起来像是 GCC 特有的问题。

标签: c++ operator-overloading new-operator replace


【解决方案1】:

在 MacOS X 10.4.11(古老 - 但计算机也是如此)上使用 GCC 4.0.1,带有“test.h”的示例有效 - 或者我对它的改编。看来您可以拥有任意数量的(相同的)“size_t”全局类型定义 - 我有 5 个,版本为 stddef.h

main 中的第一个 typedef '显然'是合法的;它是一个新的范围,可以为名称定义新的含义。

C99 基本原理说:

在 C89 中,可以在内部块中重新声明 typedef,其声明显式包含类型名称。该规则避免了是否将 typedef 作为类型名称或重新声明的候选者的歧义。在 C99 中,不允许隐式 int 声明,因此这种歧义 [原文如此!] 是不可能的,并且不再需要该规则。

稍后,在讨论标准标头时,它还说:

C89 委员会决定让库头文件“幂等”,也就是说,它们应该是 可包含任意次数,并且可按任意顺序包含。这一要求反映了 广泛的现有实践,可能需要在标题中使用一些保护性包装器以 例如,避免重新定义 typedef。为了确保这种保护性包装可以 为了工作,并确保 typedef 的正确范围,标准头文件只能包含在任何声明之外。

因此,很明显,通常不允许在单个范围(例如文件范围)中重新定义 typedef。 因此,我认为size_t 的多个外部重新定义可能是 GCC 的一个特性或错误 - 实际上是一个特性。

如果将size_t 更改为xyz,则会出现更多错误。

【讨论】:

  • 有趣的信息,但请注意该问题标记为“C++”——不确定 C89/C99 技术是否得到尊重。
  • 问题的标题是“C/C++ ...”,问题的前半部分专门询问了“gcc”而不是“g++”。后半部分询问C++。
【解决方案2】:

我不确定在您的情况下多个 typedefs 是如何编译的。请记住,标头不会自行编译,而是与实现类一起编译。此外,您的标头缺少标头保护或#pragma once 指令。你使用什么选项?

至于放置 new -- 标准 (18.5.1.3) 明确禁止 -- 所以这是行不通的。

这里没有模式——除了重新定义已经声明的符号。

顺便说一句:您的 .c.cpp 示例都不能使用 Comeau 编译。

【讨论】:

    猜你喜欢
    • 2012-04-08
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2013-01-14
    相关资源
    最近更新 更多