这个问题是由Herb Sutter的一篇文章的回复引发的,他在那里解释了MS决定不支持/制作C99编译器,但只是采用了C++(11)标准中的C(99)功能.
一位评论者回答说:
(...)C很重要,值得至少注意一点.
有很多现有的代码是有效的C但不是有效的C++.该代码不太可能被重写(...)
因为我只使用MS C++编程,所以我真的不知道"纯粹的"C,即我没有准备好了解C++的细节 - 我正在使用的语言不在C(99)中,而且我几乎没有一些C99代码在C++编译器中无法正常工作的线索.
请注意,我知道只有C99的restrict关键字对我来说似乎有非常狭窄的应用程序和关于可变长度数组(我不确定它们有多广泛或重要).
此外,我很感兴趣是否存在任何重要的语义差异或陷阱,即C(99)代码将在C++(11)下编译,但使用C++编译器而不是C编译器执行不同的操作.
快速链接:答案中的外部资源:
因此,无论我做什么,我似乎都无法避免由于我在同一项目中的多个源代码文件中包含相同的头文件而使Dev C++发出大量多重定义错误.我非常希望避免将我的所有源代码转储到一个文件中,并且只包含一次标题,因为这将使我的文件很长并且难以管理.
从本质上讲,这是正在发生的事情:
#ifndef _myheader_h
#define _myheader_h
typedef struct MYSTRUCT{
int blah;
int blah2; } MYSTRUCT;
MYSTRUCT Job_Grunt;
MYSTRUCT *Grunt = &Job_Grunt;
MYSTRUCT Job_Uruk;
MYSTRUCT *Uruk = &Job_Grunt;
int Other_data[100];
void load_jobs();
#endif
Run Code Online (Sandbox Code Playgroud)
示例Cpp文件(它们几乎都看起来像这样):
#include "myheader.h"
void load_jobs(){
Grunt->blah = 1;
Grunt->blah2 = 14;
Uruk->blah = 2;
Uruk->blah2 = 15;
return; }
Run Code Online (Sandbox Code Playgroud)
请记住,我有大约5个包含这个标题的cpp文件,每个文件都处理头文件中找到的不同类型的结构.在这个例子中,当实际头文件中有大约4-6个不同的结构,并且有更多的成员时,只有一个结构包含几个成员.我在其中包含的所有文件都遵循您在此示例中看到的相同公式.
现在我明白了标头防护只能阻止每个单独的cpp文件多次包含头文件.似乎正在发生的事情是,当编译器在每个cpp的开头读取include时,它会再次定义头文件,这会导致它吐出以下行和行:
Multiple Definition of Uruk, first defined here
Multiple Definition of Job_Uruk, first defined here
Multiple Definition of Grunt, first defined here
Multiple Definition of Job_Grunt, first …Run Code Online (Sandbox Code Playgroud) 我对标准中的这一点不太确定.说我有三个这样的文件:
foo.h中
#include <iostream>
inline void foo();
void foo()
{
std::cout << "Foo" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
Foo.cpp中:
#include "foo.h"
void baz();
int main()
{
baz();
foo();
}
Run Code Online (Sandbox Code Playgroud)
bar.cpp
#include "foo.h"
void baz()
{
foo();
}
Run Code Online (Sandbox Code Playgroud)
现在,foo的定义将被编译为编译单元foo.o和bar.o. 如果我理解正确,内联函数将避免链接器冲突.G ++编译和链接这很好,但使用clang ++ 2.8我得到这个错误:
/tmp/cc-7RdmYP.o: In function `foo()':
bar.cpp:(.text+0x50): multiple definition of `foo()'
/tmp/cc-LW3id3.o:foo.cpp:(.text+0x50): first defined here
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
看来clang ++并不是void foo()一个内联函数.但是,当我向定义添加内联时,它确实正常工作.
我是否必须在void foo()此处添加内联以将其视为内联函数,或者这是一个clang ++错误?
为什么合法?
extern int foo = 0xF00; // Gets a warning, still compiles
extern void bar() { // No warning
int x;
}
Run Code Online (Sandbox Code Playgroud)
是否有理由允许这样做?
我有这个包含很多内联函数的头文件,编译后说:函数***的多个定义,函数看起来像这样:
inline int testab(int a, int b)
{
return a>b;
}
Run Code Online (Sandbox Code Playgroud)
在内联前添加静态后,错误消失了.这是正确的方法吗?或者我错过了什么?我以为我可以在这样的标题中设置内联函数.
我有以下源文件:
//test1.cpp
#include <iostream>
using namespace std;
inline void foo()
{
cout << "test1's foo" << endl;
}
void bar();
int main(int argc, char *argv[])
{
foo();
bar();
}
Run Code Online (Sandbox Code Playgroud)
和
//test2.cpp
#include <iostream>
using namespace std;
inline void foo()
{
cout << "test2's foo" << endl;
}
void bar()
{
foo();
}
Run Code Online (Sandbox Code Playgroud)
输出:
test1's foo
test1's foo
Run Code Online (Sandbox Code Playgroud)
咦??? 好的,所以我应该声明foos是静态的...但是这种事情不应该产生链接器错误,或者至少是警告?编译器如何从编译单元"看到"内联函数?
编辑:这是使用gcc 4.4.1.
我们没有'extern模板','模板'函数总是'隐式内联'.这还有意义吗?
我阅读并重读了C++标准中有关ODR的相关条款,但这个问题仍然对我开放.该标准规定,内联函数的定义应出现在使用它的每个翻译单元中,并且定义在几乎一页中描述的意义上应相同.它说令牌序列必须相同.它是否包含本地标识符名称?
换句话说,以下程序是否违反了ODR?(我试图用Visual Studio 2008自己测试它并获得0个错误和0个警告.但我想这并不能证明什么,因为我然后将示例改为两个完全不同的定义,仍然有0个错误和0个警告. MSVC的借口应该注意的是,违反ODR不需要正式诊断.
//main.cpp
inline int f(int);
int main(){
f(3);
}
int f(int x){
int z = x;
return z*z;
}
//other.cpp
inline int f(int xx){
int zz = xx;
return zz*zz;
}
Run Code Online (Sandbox Code Playgroud) 这是一个谜语.
想象一下,我有以下C++函数:
template<uint8_t MASK>
uint8_t Foo(uint8_t val)
{
uint8_t step = 0;
uint8_t result = 0;
if(MASK & 0x01) {result |= (val & 0x01) >> step; ++step;}
if(MASK & 0x02) {result |= (val & 0x02) >> step; ++step;}
//...etc...
if(MASK & 0x80) {result |= (val & 0x80) >> step; ++step;}
return result;
}
Run Code Online (Sandbox Code Playgroud)
当我实例化这个函数时(下面的所有值都只是示例值):
uint8_t someval = Foo<0xAA>(44);
Run Code Online (Sandbox Code Playgroud)
编译器优化了Foo()中的if语句,因为它在编译时知道if()语句的结果是什么.
这很好,但是由于创建了局部变量步骤,尝试在C中执行相同操作是有问题的.
如果步骤不存在,你可以像这样做一个大的#define:
#define Foo(MASK, val) (\
((MASK & 0x01) ? (val & 0x01) : 0) | \ …Run Code Online (Sandbox Code Playgroud)