& определение оператора для массивов в C - PullRequest
4 голосов
/ 02 мая 2011

Недавний вопрос вызвал дискуссию, сосредоточенную на массивах и указателях.Вопрос касался scanf("%s", &name) против scanf("%s", name).

. Для следующего кода Microsoft фактически разрешает это для вас в VS2010 (и, возможно, в более ранних версиях?),

#include <stdio.h>

int main()
{
    char name[30];

    printf("Scan \"name\" - ");
    scanf("%s", name);
    printf("Print \"&name\" - %s\n", &name);
    printf("Print \"name\"  - %s\n", name);

    printf("Pointer to &name - %p\n", &name);
    printf("Pointer to name  - %p\n", name);

    printf("\n\n");

    printf("Scan \"&name\" - ");
    scanf("%s", &name);
    printf("Print \"&name\" - %s\n", &name);
    printf("Print \"name\"  - %s\n", name);

    printf("Pointer to &name - %p\n", &name);
    printf("Pointer to name  - %p\n", name);

    return 0;
}

Это действительно определено в стандарте ANSI C, или это разрешено быть зависимым от компилятора?Это работает, потому что MS рассматривает все как C ++?Пожалуйста, пока игнорируйте проблемы переполнения буфера.

Ответы [ 2 ]

7 голосов
/ 02 мая 2011

И name, и &name должны давать одинаковый результат.Строго говоря, только name допустимо в соответствии со стандартом языка C и &name приводит к неопределенному поведению, поэтому вам обязательно следует использовать name, но на практике оба будут работать.

name - этомассив, поэтому, когда вы используете его в качестве аргумента функции (как вы делаете, когда вы передаете его в printf), он «разлагается» на указатель на свой начальный элемент (который здесь char*).

&name дает вам адрес массива;этот адрес совпадает с адресом начального элемента (поскольку не может быть байтов заполнения перед начальным элементом массива или между элементами в массиве), поэтому &name и name имеют одинаковое значение указателя.

Однако они бывают разных типов: &name имеет тип char (*)[30] (указатель на массив 30 char), а name, когда он распадается на указатель на свой начальный элемент,имеет тип char* (указатель на char, в данном случае, начальный char элемент массива name).

, поскольку они имеют одинаковое значение, а с * 1028Функции * и scanf все равно интерпретируют аргумент как char*, не должно быть никакой разницы, передаете ли вы name или &name.

2 голосов
/ 02 мая 2011

Неопределенное поведение в соответствии со стандартом.

Спецификатор преобразования printf "%p" ожидает void*: все остальное вызывает UB Спецификатор преобразования printf "%s" ожидает char*, который включает нулевой байт где-то внутри объекта, на который указывает: все остальное вызывает UB Спецификатор преобразования scanf "%s" ожидает char* с достаточным пространством для ввода и дополнительным нулевым завершающим байтом: все остальное вызывает UB

Если какая-либо реализация определяет поведение, тогда в должно быть нормально использовать эту реализацию .

Чаще всего печать char* или char(*)[30] вместо void* с printf("%p") приводит к проявлению UB, которое неотличимо от намеченного поведения.

Чаще всего печать char(*)[30] вместо char* с printf("%s") приводит к проявлению UB, которое неотличимо от намеченного поведения.

Из того, что вы говорите, видно, что MS проявление UB в этих случаях такое же, как и предполагалось.

Но это все еще неопределенное поведение.

...