a.h
foreach ($arr as $date => $companies){
echo ' <div class="Date">Bookings for '.$date.'</div>';
foreach ($companies as $company=> $students){
echo '<div class="Company">Bookings for '.$company.'</div>';
foreach ($students as $student){
echo '<div class="Student">'.$student.'</div>';
}
}
}
交流
void addr(void);
b.c
#include <stdio.h>
int x;
void addr(void) {
printf("a:x=%p\n", &x);
}
为什么编译器或链接器不会抱怨两个具有不同类型和相同标识符( x )的extern声明,而它们却默默地链接在一起?
环境:
#include <stdio.h>
#include "a.h"
char x;
int main(void) {
addr(); /* a:x=0x601044 */
printf("b:x=%p\n", &x); /* b:x=0x601044 */
return 0;
}
答案 0 :(得分:6)
int x;
中的声明a.c
和char x;
中的b.c
只是标识符x
的临时定义。
C11标准草案N1570指出:
6.9.2外部对象定义
...
2声明对象的标识符,该对象的文件范围为,没有初始化程序,并且没有存储类说明符或具有存储类说明符为静态,构成了一个临时定义 >。
如果您同时在两个文件中都初始化了x
(类似于int x = 2;
中的a.c
和char x = '1';
中的b.c
,它们将成为“完整”定义,并且那么您将在链接器中遇到多个定义错误。
类似的东西:
Error LNK1169 one or more multiply defined symbols found
Error LNK2005 x already defined in a.obj
答案 1 :(得分:4)
C标准没有定义两次定义具有外部链接的标识符的行为。通常将某些行为定义为对C的扩展,尤其是在Unix系统上。但是,此扩展依赖于具有兼容类型的定义。通常没有定义int x;
和char x;
的结果。
两次定义带有外部链接的标识符违反了C标准中的约束,在C 2018 6.9 5中(加粗):
如果在表达式中使用了用外部链接声明的标识符(不是作为
sizeof
或_Alignof
运算符的操作数的一部分,其结果是整数常量),则在整个程序中的某个位置该标识符应完全是一个外部定义;否则,最多只能有一个。
在您的程序中,x
用于表达式&x
,因此上述约束适用:x
必须有一个外部定义。当违反约束时,根据C 2018 4 2,C标准不会定义结果行为。
为什么int x;
和char x;
的行为不同于int x = 0;
和char x = 0;
?有人可能认为它们应该是相同的,因为前者是暂定的定义(因为它们没有存储类说明符或初始化程序),并且C 2018 6.9.2 2说:
如果翻译单元包含一个或多个标识符的临时定义,并且翻译单元不包含该标识符的外部定义,则该行为就好像该翻译单元包含该标识符的文件范围声明,并且从转换单元末尾开始的复合类型,其初始值设定项等于0。
有两个原因。第一个是关于违反约束的规则,该约束导致C标准未定义的行为是覆盖规则;它比有关暂定定义的规则优先。
第二个是,尽管C标准没有定义行为,但是其他文档也可以定义它。正如C 2018 J.5.11(该信息部分而非标准的规范性部分)所指出的那样,对C语言的常见扩展是允许多个外部定义。通常,定义的类型应该一致,并且只能初始化一种。
例如,Systems V Application Binary Interface
描述了在混合有 strong 和 weak 定义或混合有 common 和非公共定义的情况下如何协调多个定义。编译器通过生成一个目标文件来与C的这种扩展配合使用,该目标文件根据标识符具有常规定义还是只是临时定义来对标识符进行不同的标记。例如,使用Apple LLVM 10.0.0和clang-1000.11.45.5 for x86_64编译包含char x;
的文件会生成标记为{common section}的符号x
,但是编译包含int x = 0;
的文件产生标记为x
的常规部分。 (将nm
命令应用于编译器生成的目标文件时,这些部分分别显示C
和S
。)
结果是:
x
并不是C标准所定义的。x
的多个临时定义以及最多一个常规定义。x
定义int
在另一位置用char
定义'use strict';
var tasks = [
{
"title": "home",
"color": "blue",
},
{
"title": "city",
"color": "green",
},
的行为是不正确的,但链接器无法对其进行诊断。