我对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中:)。答案 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进行编译。