Почему char * обрабатывается так же, как char ** в C? - PullRequest
5 голосов
/ 06 октября 2011

У меня есть следующее тестовое приложение:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main(void){
    char buf[512];
    buf[0]= 0x1;
    buf[1]= 0x2;
    char *temp1 = &buf;
    char *temp2 = buf;
    char *temp3 = &buf[0];
    printf("temp1:%p, temp2:%p, temp3:%p\n",temp1,temp2,temp3);
    printf("0 = %d, %d, %d\n",temp1[0],temp2[0],temp3[0]);
    printf("1 = %d, %d, %d\n",temp1[1],temp2[1],temp3[1]);
    return;
}

Компилируется с предупреждением:

gcc ./testptr.c -o testptr
./testptr.c: In function ‘main’:
./testptr.c:9: warning: initialization from incompatible pointer type

Но когда я запускаю его, все три указателя ведут себя одинаково.

./testptr
temp1:0x7fff3a85f220, temp2:0x7fff3a85f220, temp3:0x7fff3a85f220
0 = 1, 1, 1
1 = 2, 2, 2

Я знаю, что buf == &buf[0], но почему &buf == &buf[0]? Разве &buf не должен быть char**?

Ответы [ 4 ]

3 голосов
/ 06 октября 2011

Все указатели ведут себя одинаково, потому что вы объявили все они равными char*.Тип C статически типизирован, поэтому тип связан с переменной, а не со значением.

Теперь, когда объясняется часть поведения, нам нужно только выяснить, почему они на самом деле имеют одинаковое значение (согласно% pPrintf).Ну, это всего лишь артефакт указателей, реализуемых GCC как адрес памяти (смещения и размеры, отличающие * от **, обрабатываются системой типов / компилятором за кулисами).Обратите внимание, что, как и любой из самых подозрительных элементов, выдающих предупреждения, это может быть неопределенным поведением или, по крайней мере, плохой практикой:)

2 голосов
/ 06 октября 2011

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

1 голос
/ 06 октября 2011

Если вы думаете о том, какой код на самом деле генерируется компилятором при обработке массива, он становится более понятным.Имя buf ссылается на адрес первого (нулевого) элемента массива (непрерывное пространство для размещения символов).Если вы посмотрите на объект в записи таблицы символов для «buf», вы найдете адрес этого первого элемента.Когда вы ссылаетесь, например, на buf [0], компилятор генерирует адрес buf, плюс нулевой размер символа.Это совпадает с адресом самого buf. * ​​1001 *

1 голос
/ 06 октября 2011

Вы можете решить это из алгебры операторов * и &.

  • мы знаем, что buf является адресом 0-го элемента массива buf

  • мы знаем, что &buf[0] также является адресом 0-го элемента

  • по определению buf[0] эквивалентно *(buf+0)

  • и &(*(a)) эквивалентны a.

Итак, &buf[0] становится &(*(buf+0)), что составляет buf.

Обновление

Вот, давайте выложим это как доказательство.

  1. &buf[0] Дано.
  2. &(buf[0]) по правилам приоритета C с () 's
  3. &((*(buf+0))) потому что buf[0] == *(buf+0).
  4. &(*(buf+0)) устранение посторонних паренов
  5. buf КЭД
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...