C / C ++替换/重新定义规则?

时间:2009-04-18 04:01:06

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

我对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;
}

(更换标准新操作符适用于上述所有情况。我知道更换替换新操作符是非法的。)

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


感谢您的回复。我省略了一些代码,包括标题保护。在最后一个.cc示例中,我编码了HTML&lt;&lt;作为&amp; g t; &安培; g t;错误地忘了包含cstdlib。 我修改了代码以便编译。然而,我省略的另一件事是#define _NEW,这被证明是至关重要的。显然在GNU中&lt; new&gt;的标题保护定义_NEW,所以我在这里定义它阻止了标准新标题的包含,所以我替换了工作

m@m:~/Desktop/Library$ ./a.out 
PLACEMENT NEW CALLED
OPERATOR NEW CALLED

所以是的,唯一没有解释的是我怎么能多次在.c / .cc文件中重新输入def东西,但不是像.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中:)。

2 个答案:

答案 0 :(得分:3)

在MacOS X 10.4.11上使用GCC 4.0.1(古老 - 但也就是计算机),“test.h”的例子可行 - 或者我对它的改编。看来你可以拥有尽可能多的(相同的)'size_t'的全局类型定义 - 我在stddef.h中有5个版本。

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

C99理由说:

  

在C89中,可以在内部块中重新声明typedef,并使用明确包含类型名称的声明。此规则避免了关于是否将typedef作为类型名称或重新声明的候选者的含糊不清。在C99中,不允许使用隐式int声明,因此不可能使用此sabiguity [sic!]并且不再需要该规则。

稍后,讨论标准标题,它还说:

  

C89委员会决定使图书馆标题“是幂等的”,也就是说,它们应该是   可包括任意次数,并可按任何顺序包含。这个要求反映了这一点   广泛存在的做法,可能需要在标题内的一些保护性包装   例如,避免重新定义typedef。确保这种保护性包装可以   为了正常工作,并确保正确确定typedef的范围,标准标题只能包含在任何声明之外。

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

如果您将size_t更改为xyz,则会收到更多错误。

答案 1 :(得分:2)

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

至于展示位置new - 标准明确禁止它(18.5.1.3) - 因此无效。

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

顺便说一句:您的.c.cpp个例子都没有使用Comeau进行编译。