Глобальная переменная, которая указывает на расположение элемента в глобальном массиве (в C) - PullRequest
1 голос
/ 17 февраля 2012

Допустим, у нас есть массив, определенный как глобальная переменная.

int array[] = {16, 25, 36, 49, 64};

Если это скомпилировано как разделяемая библиотека, компилятор создаст двоичный файл с символом «массив», указывающим на расположение в памяти массива.

Можно ли добавить глобальную переменную, которая будет представлять область памяти, которая находится внутри массива.

int elem;

Может ли быть так, что elem представляет то же место, что и массив [2]? Это вообще возможно только с C?

EDIT:

Можно ли это сделать без привлечения указателей? Я заинтересован в том, чтобы elem был местом в памяти массива ведьм [2]. При int* elem = &array[2] память выделяется для указателя, и elem становится символом для этого указателя, а затем в нее помещается адрес памяти массива [2]. Я хотел бы, чтобы elem стал символом для местоположения массива [2], чтобы assert(elem == array[2]) проходил всегда . Как личность в математике (≡).

Кто-нибудь знает, что меня интересует, возможно ли это в простом C или только в сборке.

Ответы [ 6 ]

4 голосов
/ 17 февраля 2012

Конечно:

// lib.c

int array[] = { 1, 2, 3 };
int * const p = array + 2;
// lib.h

extern int array[];
extern int * const p;
1 голос
/ 17 февраля 2012

Уродливый взлом препроцессора позволяет использовать ELEM2, как массив [2].На самом деле это это массив [2]:

int array[] = {16, 25, 36, 49, 64};
#define ELEM2 (array[2])

Теперь ELEM2 даже lvalue:

ELEM2 = 42;

int *p = &ELEM2;

/* don't try this at home */

Кстати, хотя это ужасно, в основном это какstdin, stdout и stderr # определены в большинстве реализаций (на самом деле: все реализации, которые я видел)

ОБНОВЛЕНИЕ: хотя это и ужасный хак, он позволяет компилятору ловить проблемы с псевдонимами, подобные этой:

array[2] = ELEM2++ * array[2]; /* no intervening sequence points here */
1 голос
/ 17 февраля 2012
int array[] = {16, 25, 36, 49, 64};

int *elem = array + n;
0 голосов
/ 17 февраля 2012

Это невозможно в обычном C без использования указателя.

Однако вы можете использовать некоторую хитрость компоновщика для достижения этого (имейте в виду, что это не переносимо и очень, очень хакерски): получите линкер по умолчаниюСценарий из ld -verbose и отредактируйте его, включив в него что-то вроде elem = (array) + 4 * 2;, затем скомпилируйте с -Wl,-Tyour_script.ld.elem теперь должен занимать тот же адрес памяти, что и array + 8 байт (что составляет array[2] при условии sizeof(int) == 4):

 $ cat a.c
 #include <stdio.h>

 int foo[4] = {1,2,3,4};

 int bar;

 int main() {
    printf("%p %p\n", &foo[2], &bar);
    return 0;
 }
 $ gcc -Wl,-Ta.ld a.c
 $ ./a.out
 0x6008e8 0x6008e8
 $
0 голосов
/ 17 февраля 2012

Да, вы можете

int array[] = {16, 25, 36, 49, 64};
int * elem = &array[2];

int main()
{
    printf("array: %p elem: %p", array, elem);
    return 0;
}
0 голосов
/ 17 февраля 2012

Примерно так:

int * elem = &array[2];
...