2013-06-05 3 views
1

Я нашел это объявление в программе CОбъясните объявление переменной в C

char huge * far *p; 

Объяснение: р огромный указатель, * р далеко указатель и ** р голец тип переменных данных.

Просьба пояснить декларацию более подробно.

PS: Я не спрашиваю здесь об огромном или дальнем указателе. Я новичок в программировании

+6

'огромный' и' far' являются нестандартными анахронизмами - просто подумайте об этом как 'char ** p;' –

+0

Спасибо за комментарий Paul. 'почему * p - дальний указатель, а p - огромный указатель ... его сбивает с толку. – dotslash

+0

Я ясно понимаю, что ** p - переменная данных типа char. – dotslash

ответ

2

Огромные и дальние указатели не являются частью стандарта C. Они являются расширениями borland для языка C для управления сегментированной памятью в DOS и Windows 16/32bit. Функционально, что говорит декларация ** p, является символом. Это означает, что «разыменования р, чтобы получить указатель на символ, разыменования, что, чтобы получить символ»

Для того, чтобы понять, C указатель описателя семантика попробовать это выражение вместо:

int* p; 

Это означает, что р является указателем внутр. (подсказка: читать справа налево)

int* const p; 

Это означает, что р константный указатель на Int. (Так что вы не можете изменить значение р) Вот доказательство того, что:

p= 42; // error: assignment of read-only variable ‘p’ 

Другой пример:

int* const* lol; 

Это означает, лол указатель на константный указатель на Int. Таким образом, указатель, на который указывает lol, не может указывать на другой int.

lol= &p; // and yes, p cannot be reassigned, so we are correct. 

В большинстве случаев чтение справа налево имеет смысл. Теперь прочитайте выражение в вопросе справа налево:

char huge * far *p; 

Теперь огромный и далеко только поведение спецификаторы для указателей, созданных Борланд. Что это на самом деле означает

char** p; 

«р является указателем на указатель на символ»

Это означает, что все, что р указывает на, указывает на символ.

+0

спасибо. Я понимаю немного, но «почему» p - дальний указатель, а p - огромный указатель »... его сбивает с толку. – dotslash

+0

@ user2268849 обновлено – nurettin

+0

спасибо ... nurettin – dotslash

1

Вернувшись в 16-битные дни на 8086, он объявил бы 32-битный указатель на «нормализованный» 32-разрядный указатель на char (или на первый из его массива).

Разница существует, поскольку 32-разрядные указатели состоят из номера сегмента и смещения между этим сегментом, а сегменты перекрываются (что означает, что два разных указателя могут указывать на один и тот же физический адрес, например: 0x1200:1000 и 0x1300:0000). Квалификатор huge принудительно нормализовал с использованием наивысшего номера сегмента (и, следовательно, самого низкого возможного смещения).

Однако эта нормализация имела точки зрения производительности затрат, так как после каждой операции, модифицированного указатель, компилятор должен автоматически вставить такой код:

ptr = normalize(ptr); 

с:

void huge * normalize(void huge *input) 
{ 
    unsigned long input2 = (unsigned long)input; 
    unsigned short segment = input >> 16; 
    unsigned short offset = (unsigned short)input; 

    segment += (offset >> 4); 
    offset &= 0x000F; 

    return ((unsigned long)segment) << 16 | offset; 
} 

Положительным моментом было использование вашей памяти, как будто она была плоской, не беспокоясь о сегментах и ​​смещениях.

2

** p является символом. Теперь указатель, указывающий на адрес этого символа, будет иметь значение & (** p). Опять же, если вы хотите взять указатель на этот указатель, тогда будет & (* p), и результат будет только p.

Если вы прочтете ниже предложений справа налево, вы получите весь этот

р огромного указателя, * р далеко указателя и ** р переменных данных символа типа.

В двух словах виртуальные адреса на чипе Intel x86 имеют два компонента - селектор и смещение. Селектор представляет собой индекс в таблицу базовых адресов [2], и смещение добавляется к этому базовому адресу. Это было спроектировано так, чтобы позволить процессору получить доступ к 20-битным (на 8086/8, 186), 30-битным (286) или 46-битным (386 и более поздних) виртуальных адресных пространствах без больших регистраций.

«дальние» указатели имеют явный селектор. Однако, когда вы выполняете арифметику указателей на них, селектор не изменяется.

«Огромные» указатели имеют явный селектор. Когда вы выполняете арифметику указателей на них, хотя селектор может измениться.

+0

В исходном вопросе ничего не сказано о том, что этот код предназначен для ПК Intel. – Lundin

+0

+1 для уточнения меня: «p - огромный указатель, * p - дальний указатель и ** p - переменная данных типа символа». почему p - огромный указатель, почему бы не pp? – dotslash

+0

@ Lundin да, вы правы. Я просто взял x86 в качестве примера. –

0

Разъяснение к другим ответам:

far ключевое слово не является стандартным C, но это не просто старый устаревшее расширение с древних времен ПК. Сегодня существует много современных 8 и 16-разрядных процессоров, которые используют «банковскую» память для расширения объема адресной памяти за пределами 65 тыс. Обычно они используют специальный регистр для выбора банка памяти, фактически заканчивая 24-разрядными адресами. Все мелкие микроконтроллеры на рынке с RAM + флэш-памятью> 64 КБ используют такие функции.

Смежные вопросы