看起来像__attribute__((weak))
和#include <stdio.h>
extern const int weaksym1;
const int weaksym1 __attribute__(( weak )) = 0;
extern const int weaksym2;
const int weaksym2 __attribute__(( weak )) = 0;
extern int weaksym3;
int weaksym3 __attribute__(( weak )) = 0;
void testweak(void)
{
if ( weaksym1 == 0 )
{
printf( "0\n" );
}
else
{
printf( "1\n" );
}
printf( "%d\n", weaksym2 );
if ( weaksym3 == 0 )
{
printf( "0\n" );
}
else
{
printf( "1\n" );
}
}
的GCC会产生不同的结果,具体取决于您引用弱符号的方式。考虑一下:
$ cat weak.c
extern const int weaksym1;
const int weaksym1 = 1;
extern const int weaksym2;
const int weaksym2 = 1;
extern int weaksym3;
int weaksym3 = 1;
extern void testweak(void);
void main(void)
{
testweak();
}
$ cat test.c
gcc -c weak.c
gcc -c test.c
gcc -o test test.o weak.o
$ make
1
1
1
$ ./test
gcc -O2 -c weak.c
gcc -O2 -c test.c
gcc -O2 -o test test.o weak.o
$ make ADD_FLAGS =“ - O2”
0
1
1
$ ./test
use strict;
use warnings;
use Data::Dumper;
my @array;
my %hash;
$hash{'key1'} = 1;
$hash{'key2'} = 2;
$hash{'key3'} = 3;
$hash{'key4'} = 4;
push @array, {%hash};
$hash{'key1'} = 10;
$hash{'key2'} = 20;
$hash{'key3'} = 30;
$hash{'key4'} = 40;
push @array, {%hash};
# Expect:
# @array[0] like 1,2,3,4
# @array[1] like 10,20,30,40
print Dumper(@array);
doChange(\@array[1]); # <<==== THIS IS THE BIT WHERE I NEED ASSISTANCE TO PASS ARRAY ELEMENT BY REFERENCE, IF POSSIBLE
# Expect:
# @array[0] like 1,2,3,4
# @array[1] like 100,200,300,400 <<== VALUES HAVE CHANGED
print Dumper(@array);
sub doChange
{
my %h = @_; # <<=== THIS IS NOT RIGHT EITHER!?
$h{'key1'} = 100;
$h{'key2'} = 200;
$h{'key3'} = 300;
$h{'key4'} = 400;
}
问题是,为什么最后一个“./test”产生“0 1 1”,而不是“1 1 1”?
gcc版本5.4.0(GCC)
答案 0 :(得分:2)
在进行优化时,编译器在声明const
且在同一编译单元中具有weak
定义的符号时遇到问题。
您可以创建一个单独的c文件并在那里移动const弱定义,它将解决问题:
weak_def.c
const int weaksym1 __attribute__(( weak )) = 0;
const int weaksym2 __attribute__(( weak )) = 0;
此问题中描述的相同问题:GCC weak attribute on constant variables
答案 1 :(得分:1)
要点:
如果未将符号初始化为某个值,则弱符号只能正常工作。链接器负责初始化(如果不存在同名的普通符号,它总是将它们初始化为零)。
如果您尝试将弱符号初始化为任何值,即使为OP也将其初始化为零,C编译器可以自由地对其值进行奇怪的假设。编译器在弱符号和普通符号之间没有区别;它是所有(动态)链接器魔术。
要修复,请从您声明为弱的任何符号中删除初始化(= 0
):
extern const int weaksym1;
const int weaksym1 __attribute__((__weak__));
extern const int weaksym2;
const int weaksym2 __attribute__((__weak__));
extern int weaksym3;
int weaksym3 __attribute__((__weak__));
详细说明:
C语言没有“weak symbol”的概念。它是由ELF文件格式提供的功能,以及使用ELF文件格式的(动态)链接器。
由于man 1 nm
手册页在"V"
部分描述,
当弱定义符号与正常定义的符号链接时, 使用正常定义的符号,没有错误。当一个弱的未定义符号 是链接的,符号未定义,弱符号的值 变为零,没有错误。
弱符号声明不应初始化为任何值,因为如果进程未与同名的普通符号链接,则其值为零。 (man 1 nm
页面中的“defined”指的是ELF符号表中存在的符号。)
“弱符号”功能旨在与现有的C编译器配合使用。请记住,C编译器在“弱”和“正常”符号之间没有任何区别。
为确保在不与C编译器行为相冲突的情况下工作,“弱”符号必须未初始化,以便C编译器不能对其值进行任何假设。相反,它会像往常一样生成获取符号地址的代码 - 这就是普通/弱符号查找魔法发生的地方。
这也意味着弱符号只能“自动初始化”为零,而不是任何其他值,除非被正常的,同名的初始化符号“覆盖”。