C在不同文件中定义的相同全局变量

时间:2022-11-05 19:41:17

I am reading this code from here(in Chinese). There is one piece of code about testing global variable in C. The variable a has been defined in the file t.h which has been included twice. In file foo.c defined a struct b with some value and a main function. In main.c file, defined two variables without initialized.

我正在这里阅读这段代码(中文)。有一段关于在C中测试全局变量的代码。变量a已在文件t.h中定义,该文件已被包含两次。在文件foo.c中定义了一个带有一些值和一个main函数的struct b。在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",
        &a, &b, &c, sizeof b, b, c);
    return 0;
}

After using Ubuntu GCC 4.4.3 compiling, the result is like this below:

使用Ubuntu GCC 4.4.3编译后,结果如下:

foo:    (&a)=0x0804a024
    (&b)=0x0804a014
    sizeof(b)=8
    b.a=2
    b.b=4
    main:0x080483e4
main:   (&a)=0x0804a024
    (&b)=0x0804a014
    (&c)=0x0804a028
    size(b)=4
    b=2
    c=0

Variable a and b has the same address in two function, but the size of b has changed. I can't understand how it worked!

变量a和b在两个函数中具有相同的地址,但是b的大小已经改变。我无法理解它是如何工作的!

6 个解决方案

#1


19  

You are violating C's "one definition rule", and the result is undefined behavior. The "one definition rule" is not formally stated in the standard as such. We are looking at objects in different source files (aka, translation units), so we concerned with "external definitions". The "one external definition" semantic is spelled out (C11 6.9 p5):

您违反了C的“一个定义规则”,结果是未定义的行为。 “一个定义规则”在标准中没有正式陈述。我们正在查看不同源文件(也就是翻译单元)中的对象,因此我们关注“外部定义”。 “一个外部定义”语义被拼写出来(C11 6.9 p5):

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

外部定义是外部声明,它也是函数(内联定义除外)或对象的定义。如果有外部链接声明的标识符在表达式中被使用(除了作为的sizeof或_Alignof操作,其结果是一个整常数的操作数的一部分),某处在整个程序须有使标识符恰好一个外部定义;否则,不得超过一个。

Which basically means you are only allowed to define an object at most once. (The otherwise clause allows you to not define an external object at all if it is never used anywhere in the program.)

这基本上意味着您只能被允许最多定义一次对象。 (如果从未在程序中的任何地方使用过,则else子句允许您根本不定义外部对象。)

Note that you have two external definitions for b. One is the structure that you initialize in foo.c, and the other is the tentative definition in main.c, (C11 6.9.2 p1-2):

请注意,b有两个外部定义。一个是你在foo.c中初始化的结构,另一个是main.c中的暂定定义,(C11 6.9.2 p1-2):

If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

如果对象的标识符声明具有文件范围和初始化程序,则声明是标识符的外部定义。

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

具有文件范围而没有初始化程序且没有存储类说明符或存储类说明符为静态的对象的标识符声明构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。

So you have multiple definitions of b. However, there is another error, in that you have defined b with different types. First note that multiple declarations to the same object with external linkage is allowed. However, when the same name is used in two different source files, that name refers to the same object (C11 6.2.2 p2):

所以你有多个b的定义。但是,还有另一个错误,因为您已使用不同类型定义了b。首先请注意,允许使用外部链接对同一对象进行多次声明。但是,当在两个不同的源文件中使用相同的名称时,该名称引用相同的对象(C11 6.2.2 p2):

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function.

在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能。

C puts a strict limitation on declarations to the same object (C11 6.2.7 p2):

C对同一对象的声明设置了严格的限制(C11 6.2.7 p2):

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

引用同一对象或函数的所有声明都应具有兼容类型;否则,行为未定义。

Since the types for b in each of your source files do not actually match, the behavior is undefined. (What constitutes a compatible type is described in detail in all of C11 6.2.7, but it basically boils down to being that the types have to match.)

由于每个源文件中的b类型实际上不匹配,因此行为未定义。 (在C11 6.2.7的所有内容中都详细描述了兼容类型的构成,但它基本上归结为类型必须匹配。)

So you have two failings for b:

所以你有两个b的失败:

  • Multiple definitions.
  • 多个定义。
  • Multiple declarations with incompatible types.
  • 具有不兼容类型的多个声明。

Technically, your declaration of int a in both of your source files also violates the "one definition rule". Note that a has external linkage (C11 6.2.2 p5):

从技术上讲,您在两个源文件中声明int a也违反了“一个定义规则”。注意a有外部链接(C11 6.2.2 p5):

If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

如果对象的标识符声明具有文件范围而没有存储类说明符,则其链接是外部的。

But, from the quote from C11 6.9.2 earlier, those int a tentative definitions are external definitions, and you are only allowed one of those from the quote from C11 6.9 at the top.

但是,从前面C11 6.9.2的引用来看,暂定定义中的那些是外部定义,并且只允许其中一个来自顶部的C11 6.9的引用。

The usual disclaimers apply for undefined behavior. Anything can happen, and that would include the behavior you observed.

通常的免责声明适用于未定义的行为。任何事情都可能发生,包括你观察到的行为。


A common extension to C is to allow multiple external definitions, and is described in the C standard in the informative Annex J.5 (C11 J.5.11):

C的一个共同扩展是允许多个外部定义,并在资料性附件J.5(C11 J.5.11)的C标准中进行了描述:

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).

对象的标识符可能有多个外部定义,有或没有明确使用关键字extern;如果定义不一致,或者初始化多个,则行为未定义(6.9.2)。

(Emphasis is mine.) Since the definitions for a agree, there is no harm there, but the definitions for b do not agree. This extension explains why your compiler does not complain about the presence of multiple definitions. From the quote of C11 6.2.2, the linker will attempt to reconcile the multiple references to the same object.

(重点是我的。)由于同意的定义,没有任何伤害,但b的定义不一致。此扩展解释了为什么您的编译器不会抱怨存在多个定义。根据C11 6.2.2的引用,链接器将尝试协调对同一对象的多个引用。

Linkers typically use one of two models for reconciling multiple definitions of the same symbol in multiple translation units. These are the "Common Model" and the "Ref/Def Model". In the "Common Model", multiple objects with the same name are folded into a single object in a union style manner so that the object takes on the size of the largest definition. In the "Ref/Def Model", each external name must have exactly one definition.

链接器通常使用两个模型中的一个来协调多个转换单元中相同符号的多个定义。这些是“通用模型”和“参考/确定模型”。在“通用模型”中,具有相同名称的多个对象以联合样式方式折叠到单个对象中,以使对象具有最大定义的大小。在“Ref / Def Model”中,每个外部名称必须只有一个定义。

The GNU toolchain uses the "Common Model" by default, and a "Relaxed Ref/Def Model", where it enforces a strictly one definition rule for a single translation unit, but does not complain about violations across multiple translation units.

GNU工具链默认使用“Common Model”和“Relaxed Ref / Def Model”,它对单个翻译单元强制执行严格的一个定义规则,但不会抱怨跨多个翻译单元的违规行为。

The "Common Model" can be suppressed in the GNU compiler by using the -fno-common option. When I tested this on my system, it caused "Strict Ref/Def Model" behavior for code similar to yours:

可以使用-fno-common选项在GNU编译器中抑制“Common Model”。当我在我的系统上测试它时,它会导致类似于你的代码的“严格参考/默认模型”行为:

$ cat a.c
#include <stdio.h>
int a;
struct { char a; int b; } b = { 2, 4 };
void foo () { printf("%zu\n", sizeof(b)); }
$ cat b.c
#include <stdio.h>
extern void foo();
int a, b;
int main () { printf("%zu\n", sizeof(b)); foo(); }
$ gcc -fno-common a.c b.c
/tmp/ccd4fSOL.o:(.bss+0x0): multiple definition of `a'
/tmp/ccMoQ72v.o:(.bss+0x0): first defined here
/tmp/ccd4fSOL.o:(.bss+0x4): multiple definition of `b'
/tmp/ccMoQ72v.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `b' changed from 8 in /tmp/ccMoQ72v.o to 4 in /tmp/ccd4fSOL.o
collect2: ld returned 1 exit status
$

I personally feel the last warning issued by the linker should always be provided regardless of the resolution model for multiple object definitions, but that is neither here nor there.

我个人认为,无论多个对象定义的分辨率模型如何,都应始终提供链接器发出的最后警告,但这既不是在这里也不是在那里。


References:
Unfortunately, I can't give you the link to my copy of the C11 Standard
What are extern variables in C?
The "Beginner's Guide to Linkers"
SAS Documentation on External Variable Models

参考文献:不幸的是,我不能给你链接到我的C11标准副本什么是C中的外部变量?关于外部变量模型的“链接器初学者指南”SAS文档

#2


3  

Formally, it is illegal to define the same variable (or function) with external linkage more than once. So, from the formal point of view the behavior of your program is undefined.

在形式上,使用外部链接多次定义相同的变量(或函数)是非法的。因此,从正式的角度来看,程序的行为是不确定的。

Practically, allowing multiple definitions of the same variable with external linkage is a popular compiler extension (a common extension, mentioned as such in the language specification). However, in order to be used properly, each definition shall declare it with the same type. And no more than one definition shall include initializer.

实际上,允许使用外部链接对同一变量进行多个定义是一种流行的编译器扩展(一种常见的扩展,在语言规范中提到)。但是,为了正确使用,每个定义都应使用相同的类型声明它。并且不超过一个定义应包括初始化程序。

Your case does not match the common extension description. Your code compiles as a side effect of that common extension, but its behavior is still undefined.

您的案例与常见的扩展说明不符。您的代码编译为该公共扩展的副作用,但其行为仍未定义。

#3


2  

The piece of code seems to break the one-definition rule on purpose. It will invoke undefined behavior, don't do that.

这段代码似乎打算打破单一定义规则。它将调用未定义的行为,不要这样做。

About the global variable a: don't put definition of a global variable in a header file, since it will be included in multiple .c files, and leads to multiple definition. Just put declarations in the header and put the definition in one of the .c files.

关于全局变量a:不要将全局变量的定义放在头文件中,因为它将包含在多个.c文件中,并导致多个定义。只需将声明放在标题中,然后将定义放在其中一个.c文件中。

In t.h:

在t.h中:

extern int a;

In foo.c

在foo.c

int a;

About the global variable b: don't define it multiple times, use static to limit the variable in a file.

关于全局变量b:不要多次定义它,使用static来限制文件中的变量。

In foo.c:

在foo.c中:

static struct {
   char a;
   int b;
} b = { 2, 4 };

In main.c

在main.c

static int b;

#4


1  

b has the same address because the linker decided to resolve the conflict for you.

b具有相同的地址,因为链接器决定为您解决冲突。

sizeof shows different values because sizeof is evaluated at compile time. At this stage, the compiler only knows about one b (the one defined in the current file).

sizeof显示不同的值,因为sizeof是在编译时计算的。在此阶段,编译器只知道一个b(当前文件中定义的那个)。

#5


0  

At the time foo is being compiled, the b that is in scope is the two ints vector {2, 4} or 8 bytes when an sizeof(int) is 4. When main is compiled, b has just been redeclared as an int so a size of 4 makes sense. Also there is probably "padding bytes" added to the struct after "a" such that the next slot (the int) is aligned on 4 bytes boundary.

在编译foo时,范围内的b是sizeof(int)为4时的两个整数向量{2,4}或8个字节。当编译main时,b刚刚被重新声明为int,所以大小为4是有道理的。也可能在“a”之后向结构添加“填充字节”,使得下一个槽(int)在4字节边界上对齐。

#6


-1  

a and b have the same addresses because they occur at the same points in the file. The fact that b is a different size doesn't matter where the variable begins. If you added a variable c between a and b in one of the files, the address of the bs would differ.

a和b具有相同的地址,因为它们出现在文件中的相同点。 b是不同大小的事实与变量开始的位置无关。如果在其中一个文件中的a和b之间添加了变量c,则bs的地址会有所不同。

#1


19  

You are violating C's "one definition rule", and the result is undefined behavior. The "one definition rule" is not formally stated in the standard as such. We are looking at objects in different source files (aka, translation units), so we concerned with "external definitions". The "one external definition" semantic is spelled out (C11 6.9 p5):

您违反了C的“一个定义规则”,结果是未定义的行为。 “一个定义规则”在标准中没有正式陈述。我们正在查看不同源文件(也就是翻译单元)中的对象,因此我们关注“外部定义”。 “一个外部定义”语义被拼写出来(C11 6.9 p5):

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

外部定义是外部声明,它也是函数(内联定义除外)或对象的定义。如果有外部链接声明的标识符在表达式中被使用(除了作为的sizeof或_Alignof操作,其结果是一个整常数的操作数的一部分),某处在整个程序须有使标识符恰好一个外部定义;否则,不得超过一个。

Which basically means you are only allowed to define an object at most once. (The otherwise clause allows you to not define an external object at all if it is never used anywhere in the program.)

这基本上意味着您只能被允许最多定义一次对象。 (如果从未在程序中的任何地方使用过,则else子句允许您根本不定义外部对象。)

Note that you have two external definitions for b. One is the structure that you initialize in foo.c, and the other is the tentative definition in main.c, (C11 6.9.2 p1-2):

请注意,b有两个外部定义。一个是你在foo.c中初始化的结构,另一个是main.c中的暂定定义,(C11 6.9.2 p1-2):

If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

如果对象的标识符声明具有文件范围和初始化程序,则声明是标识符的外部定义。

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

具有文件范围而没有初始化程序且没有存储类说明符或存储类说明符为静态的对象的标识符声明构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。

So you have multiple definitions of b. However, there is another error, in that you have defined b with different types. First note that multiple declarations to the same object with external linkage is allowed. However, when the same name is used in two different source files, that name refers to the same object (C11 6.2.2 p2):

所以你有多个b的定义。但是,还有另一个错误,因为您已使用不同类型定义了b。首先请注意,允许使用外部链接对同一对象进行多次声明。但是,当在两个不同的源文件中使用相同的名称时,该名称引用相同的对象(C11 6.2.2 p2):

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function.

在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能。

C puts a strict limitation on declarations to the same object (C11 6.2.7 p2):

C对同一对象的声明设置了严格的限制(C11 6.2.7 p2):

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

引用同一对象或函数的所有声明都应具有兼容类型;否则,行为未定义。

Since the types for b in each of your source files do not actually match, the behavior is undefined. (What constitutes a compatible type is described in detail in all of C11 6.2.7, but it basically boils down to being that the types have to match.)

由于每个源文件中的b类型实际上不匹配,因此行为未定义。 (在C11 6.2.7的所有内容中都详细描述了兼容类型的构成,但它基本上归结为类型必须匹配。)

So you have two failings for b:

所以你有两个b的失败:

  • Multiple definitions.
  • 多个定义。
  • Multiple declarations with incompatible types.
  • 具有不兼容类型的多个声明。

Technically, your declaration of int a in both of your source files also violates the "one definition rule". Note that a has external linkage (C11 6.2.2 p5):

从技术上讲,您在两个源文件中声明int a也违反了“一个定义规则”。注意a有外部链接(C11 6.2.2 p5):

If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

如果对象的标识符声明具有文件范围而没有存储类说明符,则其链接是外部的。

But, from the quote from C11 6.9.2 earlier, those int a tentative definitions are external definitions, and you are only allowed one of those from the quote from C11 6.9 at the top.

但是,从前面C11 6.9.2的引用来看,暂定定义中的那些是外部定义,并且只允许其中一个来自顶部的C11 6.9的引用。

The usual disclaimers apply for undefined behavior. Anything can happen, and that would include the behavior you observed.

通常的免责声明适用于未定义的行为。任何事情都可能发生,包括你观察到的行为。


A common extension to C is to allow multiple external definitions, and is described in the C standard in the informative Annex J.5 (C11 J.5.11):

C的一个共同扩展是允许多个外部定义,并在资料性附件J.5(C11 J.5.11)的C标准中进行了描述:

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).

对象的标识符可能有多个外部定义,有或没有明确使用关键字extern;如果定义不一致,或者初始化多个,则行为未定义(6.9.2)。

(Emphasis is mine.) Since the definitions for a agree, there is no harm there, but the definitions for b do not agree. This extension explains why your compiler does not complain about the presence of multiple definitions. From the quote of C11 6.2.2, the linker will attempt to reconcile the multiple references to the same object.

(重点是我的。)由于同意的定义,没有任何伤害,但b的定义不一致。此扩展解释了为什么您的编译器不会抱怨存在多个定义。根据C11 6.2.2的引用,链接器将尝试协调对同一对象的多个引用。

Linkers typically use one of two models for reconciling multiple definitions of the same symbol in multiple translation units. These are the "Common Model" and the "Ref/Def Model". In the "Common Model", multiple objects with the same name are folded into a single object in a union style manner so that the object takes on the size of the largest definition. In the "Ref/Def Model", each external name must have exactly one definition.

链接器通常使用两个模型中的一个来协调多个转换单元中相同符号的多个定义。这些是“通用模型”和“参考/确定模型”。在“通用模型”中,具有相同名称的多个对象以联合样式方式折叠到单个对象中,以使对象具有最大定义的大小。在“Ref / Def Model”中,每个外部名称必须只有一个定义。

The GNU toolchain uses the "Common Model" by default, and a "Relaxed Ref/Def Model", where it enforces a strictly one definition rule for a single translation unit, but does not complain about violations across multiple translation units.

GNU工具链默认使用“Common Model”和“Relaxed Ref / Def Model”,它对单个翻译单元强制执行严格的一个定义规则,但不会抱怨跨多个翻译单元的违规行为。

The "Common Model" can be suppressed in the GNU compiler by using the -fno-common option. When I tested this on my system, it caused "Strict Ref/Def Model" behavior for code similar to yours:

可以使用-fno-common选项在GNU编译器中抑制“Common Model”。当我在我的系统上测试它时,它会导致类似于你的代码的“严格参考/默认模型”行为:

$ cat a.c
#include <stdio.h>
int a;
struct { char a; int b; } b = { 2, 4 };
void foo () { printf("%zu\n", sizeof(b)); }
$ cat b.c
#include <stdio.h>
extern void foo();
int a, b;
int main () { printf("%zu\n", sizeof(b)); foo(); }
$ gcc -fno-common a.c b.c
/tmp/ccd4fSOL.o:(.bss+0x0): multiple definition of `a'
/tmp/ccMoQ72v.o:(.bss+0x0): first defined here
/tmp/ccd4fSOL.o:(.bss+0x4): multiple definition of `b'
/tmp/ccMoQ72v.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `b' changed from 8 in /tmp/ccMoQ72v.o to 4 in /tmp/ccd4fSOL.o
collect2: ld returned 1 exit status
$

I personally feel the last warning issued by the linker should always be provided regardless of the resolution model for multiple object definitions, but that is neither here nor there.

我个人认为,无论多个对象定义的分辨率模型如何,都应始终提供链接器发出的最后警告,但这既不是在这里也不是在那里。


References:
Unfortunately, I can't give you the link to my copy of the C11 Standard
What are extern variables in C?
The "Beginner's Guide to Linkers"
SAS Documentation on External Variable Models

参考文献:不幸的是,我不能给你链接到我的C11标准副本什么是C中的外部变量?关于外部变量模型的“链接器初学者指南”SAS文档

#2


3  

Formally, it is illegal to define the same variable (or function) with external linkage more than once. So, from the formal point of view the behavior of your program is undefined.

在形式上,使用外部链接多次定义相同的变量(或函数)是非法的。因此,从正式的角度来看,程序的行为是不确定的。

Practically, allowing multiple definitions of the same variable with external linkage is a popular compiler extension (a common extension, mentioned as such in the language specification). However, in order to be used properly, each definition shall declare it with the same type. And no more than one definition shall include initializer.

实际上,允许使用外部链接对同一变量进行多个定义是一种流行的编译器扩展(一种常见的扩展,在语言规范中提到)。但是,为了正确使用,每个定义都应使用相同的类型声明它。并且不超过一个定义应包括初始化程序。

Your case does not match the common extension description. Your code compiles as a side effect of that common extension, but its behavior is still undefined.

您的案例与常见的扩展说明不符。您的代码编译为该公共扩展的副作用,但其行为仍未定义。

#3


2  

The piece of code seems to break the one-definition rule on purpose. It will invoke undefined behavior, don't do that.

这段代码似乎打算打破单一定义规则。它将调用未定义的行为,不要这样做。

About the global variable a: don't put definition of a global variable in a header file, since it will be included in multiple .c files, and leads to multiple definition. Just put declarations in the header and put the definition in one of the .c files.

关于全局变量a:不要将全局变量的定义放在头文件中,因为它将包含在多个.c文件中,并导致多个定义。只需将声明放在标题中,然后将定义放在其中一个.c文件中。

In t.h:

在t.h中:

extern int a;

In foo.c

在foo.c

int a;

About the global variable b: don't define it multiple times, use static to limit the variable in a file.

关于全局变量b:不要多次定义它,使用static来限制文件中的变量。

In foo.c:

在foo.c中:

static struct {
   char a;
   int b;
} b = { 2, 4 };

In main.c

在main.c

static int b;

#4


1  

b has the same address because the linker decided to resolve the conflict for you.

b具有相同的地址,因为链接器决定为您解决冲突。

sizeof shows different values because sizeof is evaluated at compile time. At this stage, the compiler only knows about one b (the one defined in the current file).

sizeof显示不同的值,因为sizeof是在编译时计算的。在此阶段,编译器只知道一个b(当前文件中定义的那个)。

#5


0  

At the time foo is being compiled, the b that is in scope is the two ints vector {2, 4} or 8 bytes when an sizeof(int) is 4. When main is compiled, b has just been redeclared as an int so a size of 4 makes sense. Also there is probably "padding bytes" added to the struct after "a" such that the next slot (the int) is aligned on 4 bytes boundary.

在编译foo时,范围内的b是sizeof(int)为4时的两个整数向量{2,4}或8个字节。当编译main时,b刚刚被重新声明为int,所以大小为4是有道理的。也可能在“a”之后向结构添加“填充字节”,使得下一个槽(int)在4字节边界上对齐。

#6


-1  

a and b have the same addresses because they occur at the same points in the file. The fact that b is a different size doesn't matter where the variable begins. If you added a variable c between a and b in one of the files, the address of the bs would differ.

a和b具有相同的地址,因为它们出现在文件中的相同点。 b是不同大小的事实与变量开始的位置无关。如果在其中一个文件中的a和b之间添加了变量c,则bs的地址会有所不同。