2013-11-17 3 views
0

Я пишу свой собственный код инициализации, который должен пересекать массив глобальных конструкторов и вызывать их. Указатели на эти конструкторы сохраняются в разделе .init_array. Мой код выглядит следующим образом:C extern pointer to function pointer

extern void (**_init_array_start)(); 
extern void (**_init_array_end)(); 


void _init() 
{ 
    void (**ctor)(); 
    for (ctor = _init_array_start ; ctor != _init_array_end ; ctor++) { 
     (*ctor)(); 
    } 
} 

внешнеположенность определена в сценарии компоновки, как это:

.init_array : 
{ 
    . = ALIGN(4); 
    _init_array_start = .; 
    KEEP(*(SORT(.init_array.*))) 
    KEEP(*(.init_array)) 
    . = ALIGN(4); 
    _init_array_end = .; 
} >rom 

Однако окончательный ассемблерный код выглядит следующим образом:

00000010 <_init>: 
    10: b538  push {r3, r4, r5, lr} 
    12: 4b05  ldr r3, [pc, #20] ; (28 <_init+0x18>) 
    14: 4d05  ldr r5, [pc, #20] ; (2c <_init+0x1c>) 
    16: 681c  ldr r4, [r3, #0] 
    18: 682b  ldr r3, [r5, #0] 
    1a: 429c  cmp r4, r3 
    1c: d003  beq.n 26 <_init+0x16> 
    1e: f854 3b04 ldr.w r3, [r4], #4 
    22: 4798  blx r3 
    24: e7f8  b.n 18 <_init+0x8> 
    26: bd38  pop {r3, r4, r5, pc} 
    28: 00000144 andeq r0, r0, r4, asr #2 
    2c: 00000150 andeq r0, r0, r0, asr r1 

Теперь, интересная часть здесь 0x16 и 0x18. Эти две команды разыгрывают _init_array_start и _init_array_end в заголовке цикла. Это не то, что я хотел. Я хочу работать с указателями на указатели функций, а не на их значения (т. Е. Указатели на функцию). Теперь, когда я изменить Экстерн заявления к следующему, два Разыменование инструкции по волшебству исчезают:

extern void (*_init_array_start[0])(); 
extern void (*_init_array_end[0])(); 

Итак, почему компилятор разыменования указателей в первую очередь, и почему это не сделать это с синтаксис массива? Разве эти два синтаксиса не должны быть эквивалентными?

ответ

0

_init_array_start Является адресом, в котором хранится первый указатель на конструктор. Вы должны взять адрес из этой переменной и перебрать по адресу _init_array_end. Если у вас есть это в виду, вам придется адаптировать типы указателей для соответствия этому подходу.

1

Символы (почти) всегда обращаются, а указатели не совпадают с массивами.

extern int* i; означает, что «символ« i »является адресом int *.» i будет означать «значение по адресу, указанному символом« i », что является разыменованием указателя. &i будет означать «адрес, указанный символом« i », которого нет.

В случае массивов "extern int a [42];" означает «символ« a »- это адрес массива из 42 целых чисел». Когда имя массива само по себе используется в C, оно ссылается на адрес массива, поэтому a здесь будет эквивалентен &i из предыдущего примера. &a также указывает на тот же адрес, но имеет другой тип. Оба имеют адрес, указанный символом «a».

Если вы не хотите использовать синтаксис массива, то первый код вы вывесили должен работать, если вы измените extern void (**_init_array_start)(); на extern void (*_init_array_start)(); и _init_array_start к &_init_array_start.

Edit: Другой способ смотреть на это, что _init_array_start не является указателем на первый инициализатор - это является первый инициализатор - так объявить его как указатель на указатель на функцию не так. Синтаксис массива объявляет его как массив указателей на функции, что и есть на самом деле.

0

Это объявление объекта указателя на тип указателя:

extern void (**_init_array_start)(); 

Это определение имени символа, связанного с началом массива:

_init_array_start = .; 

Но вы Бесполезный 't выделить хранилище для чего-либо указателя на тип указателя, только массив.

Похоже, вы можете обращаться в сторону C таким образом, вместо:

extern void (*_init_array_start)(); 
extern void (*_init_array_end)(); // One past the end; not a real object. 

void _init() 
{ 
    void (**ctor)(); 
    for (ctor = &_init_array_start ; ctor != &_init_array_end ; ctor++) { 
     (*ctor)(); 
    } 
} 

Это, вероятно, будет чище генерировать глобальное целое значение для представления размера массива, а также доступ, что из C , хотя это будет означать выделение памяти для указанного целого.