为什么我不能拥有一个; 在2个C文件中.我打算将两者结合起来制作可执行文件.我从经验中知道我不能,但我想找到标准C99所说的位置并密封我的理解.
我正在阅读http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf中的 ISO C99标准.它在第42页说:
6.2.2识别者的联系
1可以通过一个称为连接的过程,在不同的范围或相同的范围内多次声明一个标识符来引用同一个对象或函数.有三种链接:外部,内部和无.
2在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能.在一个翻译单元内,具有内部链接的标识符的每个声明表示相同的对象或功能.没有链接的标识符的每个声明表示唯一的实体.
3如果对象或函数的文件范围标识声明包含存储类指定静态,则标识符具有内部链接.
4对于在存储类规范外部声明的标识符,在该范围内可以看到该标识符的先前声明,如果先前声明指定内部或外部链接,则后面声明中标识符的链接与在先前声明中指定的联系.如果没有先前的声明可见,或者如果先前的声明没有指定链接,则标识符具有外部链接.
5如果函数的标识符声明没有存储类规范,则其链接的确定就像是使用存储类指定器extern声明的.如果对象的标识符声明具有文件范围且没有存储 - 特定的,它的联系是外在的.
看完之后看起来如果我声明一个变量就像说int a; 在2个源文件中.然后根据规则5和4都有外部链接,然后根据规则2,两者都应该引用同一个对象.那为什么编译器会产生问题.在标准中,暗示我们不能在2个源文件中声明这样,这应该抛出编译错误.首先,在标准中,它表示int a是一个定义,然后它表示2个定义实例是不可接受的.我知道我的经验是不允许的,但如果我能在标准中找到并密封我的理解,那对我来说非常有用.
请将以下标准的摘录与此规则相结合?或者我错过了胶水?:
声明规定了一组标识符的解释和属性.标识符的定义是对该标识符的声明: - 对于一个对象,导致为该对象保留存储; - 用于功能,包括功能体; - 对于枚举常量或typedef名称,是标识符的(唯一)声明.
正如5.1.1.1中所讨论的,预处理后的程序文本单元是一个翻译单元,它由一系列外部声明组成.这些被描述为"外部",因为它们出现在任何功能之外(因此具有文件范围).正如6.7中所讨论的那样,一个声明也会导致为一个对象或由标识符命名的函数保留存储,这是一个定义.
外部定义是外部声明,它也是函数(除了内联定义)或对象的定义.如果在表达式中使用了使用外部链接声明的标识符(除了作为sizeof运算符的操作数的一部分,其结果是整数常量),整个程序中的某个地方应该只有一个外部定义用于标识符; 否则,不得超过一个.
谢谢.
我有一大堆常量,我想在我的代码的不同部分访问,但我希望能够轻松访问整个:
static const bool doX = true;
static const bool doY = false;
static const int maxNumX = 5;
Run Code Online (Sandbox Code Playgroud)
等等
所以我创建了一个名为"constants.h"的文件,并将它们全部放在那里,并将#included包含在任何需要知道常量的文件中.
问题是,这对于编译时来说很糟糕,因为每次更改常量时,都必须重建constants.h引用的所有文件.(另外,据我所知,因为它们是静态的,所以每次在新的.cpp中包含constants.h时,我都会在代码中生成doX/doY/maxNumX的副本,导致在编译时浪费千字节的空间EXE - 有没有办法看到这个?).
所以,我想要一个解决方案.如果可能的话,不是"仅在使用它们的文件中声明常量".
有什么建议?
在调试一些遗留代码时,我偶然发现令人惊讶的(对我而言)编译器行为.现在我想知道C++规范中的任何子句是否允许以下优化,其中函数调用对for-condition的副作用被忽略:
void bar()
{
extern int upper_bound;
upper_bound--;
}
void foo()
{
extern int upper_bound; // from some other translation unit, initially ~ 10
for (int i = 0; i < upper_bound; ) {
bar();
}
}
Run Code Online (Sandbox Code Playgroud)
在得到的解析中,存在一个控制路径,其中upper_bound保存在寄存器中,并且upper_boundin 的递减bar()永远不会生效.
我的编译器是Microsoft Visual C++ 11.00.60610.1.
老实说,我在N3242的 6.5.3和6.5.1中没有看到太多的摆动空间,但我想确定我没有错过任何明显的东西.
我稍微浏览了一下 Stackoverflow 和更广泛的互联网,发现导致此错误的最常见原因是声明( int var = 1;) 和定义( int var;) 的合并,以及包含文件.c中的文件.h。
我刚刚从一个文件分成几个文件的小项目没有做任何这些事情。我很困惑。
我制作了该项目的副本,并删除了副本中的所有代码(这很有趣),直到到达这里:
#include "a.h"
int main() {
}
Run Code Online (Sandbox Code Playgroud)
#ifndef A_H
#define A_H
int test;
#endif
Run Code Online (Sandbox Code Playgroud)
#include "a.h"
Run Code Online (Sandbox Code Playgroud)
几乎是规范的,对吧?但是...
$ rm *.o; gcc -g -c a.c; gcc -g -c main.c; gcc -o main main.o a.o
/usr/bin/ld: a.o:/.../a.h:5: multiple definition of `test'; main.o:/.../a.h:5: first defined here
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
瓦特:(
大约在这个时候,我开始质疑我的配置,并尝试了另一台机器,通过 NFS …
我对如何在头文件中声明函数指针感到困惑.我想在main和一个名为menus.c的文件中使用它,并在menus.h中声明它.我假设.我们想要初始化以指向某个功能.
它看起来像这样:
void (*current_menu)(int);
Run Code Online (Sandbox Code Playgroud)
我们在menus.c,menus.h和main中写了什么?
我开始使用C编程了.我目前有一个包含很多功能的大文件.我想将这些函数移动到一个单独的文件,以便代码更容易阅读.但是,我似乎无法弄清楚如何正确包含/编译,并且无法在我找到的任何在线教程中找到示例.这是一个简化的例子:
#include <stdlib.h>
#include <stdio.h>
void func1(void) {
printf("Function 1!\n");
}
void func2(void) {
printf("Function 2!\n");
}
int main(void) {
func1();
func2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如何将C函数移动到单独的文件中?仅供参考:我正在使用gcc.
更新:这些答案非常有用,谢谢.现在似乎我的简化示例不够好,因为我意识到我的程序编译失败的原因是因为我在我的函数中使用了一个全局变量.
#include <stdlib.h>
#include <stdio.h>
int counter = 0;
void func1(void) {
printf("Function 1!\n");
counter++;
}
int main(void) {
func1();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将这些函数移动到外部文件不起作用,因为它们需要引用此全局变量:
#include <stdlib.h>
#include <stdio.h>
#include "functions.c"
int counter = 0;
int main(void) {
func1();
counter = 100;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题?
我在C文件中定义了一个变量:int x我知道extern int x如果我想在其他文件中使用它,我应该用它来在其他文件中声明它.
我的问题是:我应该在其他文件中将其声明在哪里?
在所有功能之外,
// in file a.c:
int x;
// in file b.c:
extern int x;
void foo() { printf("%d\n", x); }
Run Code Online (Sandbox Code Playgroud)在将使用它的功能内?
// in file b.c:
void foo() {
extern int x;
printf("%d\n", x);
}
Run Code Online (Sandbox Code Playgroud)我的怀疑是:
我创建了一个2D数组,并尝试打印某些值,如下所示:
int a[2][2] = { {1, 2},
{3, 4}};
printf("%d %d\n", *(a+1)[0], ((int *)a+1)[0]);
Run Code Online (Sandbox Code Playgroud)
输出是:
3 2
Run Code Online (Sandbox Code Playgroud)
我理解为什么3是第一个输出(a+1指向第二行,我们打印它的0th元素.
我的问题是关于第二个输出,即2.我的猜测是,由于类型转换a为int *,所述2D阵列像一维数组进行处理,并且因此a+1充当指向2nd元素,所以我们得到的输出作为2.
我的假设是正确的还是背后还有其他一些逻辑?
另外,原来什么是a被当作指针int (*)[2]或int **?的类型?
考虑一下代码:
#include <stdio.h>
int x;
int main (void)
{ }
Run Code Online (Sandbox Code Playgroud)
的价值x是0里面main.但那是为什么呢?我没有宣布它static.或者假设static它在函数之外?
如果上述情况属实,它是如何与它不同的extern?
我正在这里阅读这段代码(中文).有一段关于在C中测试全局变量的代码.该变量a已在文件t.h中定义,该文件已包含两次.在文件中foo.c定义了一个struct b带有一些值和一个main函数.在main.c文件中,定义了两个没有初始化的变量.
/* t.h */
#ifndef _H_
#define _H_
int a;
#endif
/* foo.c */
#include <stdio.h>
#include "t.h"
struct {
char a;
int b;
} b = { 2, 4 };
int main();
void foo()
{
printf("foo:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\tsizeof(b)=%d\n\tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
&a, &b, sizeof b, b.a, b.b, main);
}
/* main.c */
#include <stdio.h>
#include "t.h"
int b;
int c;
int main()
{
foo();
printf("main:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\t(&c)=0x%08x\n\tsize(b)=%d\n\tb=%d\n\tc=%d\n", …Run Code Online (Sandbox Code Playgroud)