Различная семантика между `char *` и `int *` - PullRequest
0 голосов
/ 24 сентября 2019

Я хочу знать, почему объявление и присвоение char * по сравнению с int * в C имеют различную семантику.

Весь следующий код скомпилирован с clang с использованием флагов -Wall -Werror -std=gnu99 --pedantic.Я пытаюсь понять, является ли различие чем-то, что просто равно , или есть какая-то большая разница между int * и char *, которую я еще не осознал.

// this will compile
int main(int argc, const char *argv[]) {
    char *a;
    a = "1";

    printf("a: %s\n", a);
    return EXIT_SUCCESS;
}
// this will not compile. It's a parallel construction, substituting char for int
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[]) {
    int *a;
    a = 1;

    printf("a: %d\n", a);
    return EXIT_SUCCESS;
}
// but this will compile
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[]) {
    int *a;
    int b = 1;
    a = &b;

    printf("a: %d\n", *a);
    return EXIT_SUCCESS;
}

Ответы [ 3 ]

0 голосов
/ 24 сентября 2019

Второй пример не скомпилируется, потому что у вас включен -Werror, и вы пытаетесь присвоить целое число указателю без приведения, что обычно является просто предупреждением.То же самое произошло бы, если бы вы сделали char* a; a='a';, потому что вы пытались бы назначить char для char *.

С точки зрения различной семантики между типами указателей - то, что хранится в памяти как указатель, этоскорее всего не будет отличаться, но тип указателя повлияет на компиляцию.В основном, когда дело доходит до арифметики указателей, индексации массивов и использования указателей для агрегирования (структуры) типов и функций.

Все начинает действовать иначе, когда вы начинаете использовать арифметику указателей / индексацию массивов.Например:

int value = 4
char *charp = &value;
int* intp = &value;

Оба будут действительными указателями.Вы также увидите различные варианты поведения во время компиляции, если будете работать с указателями на функции, с которыми вы можете использовать синтаксис вызова функций, и с указателями на структуры, где вы можете получить доступ к членам ссылочной структуры с помощью оператора ->.

0 голосов
/ 24 сентября 2019

Вы имеете дело с разницей между массивом, указателем и скалярной семантикой.

За исключением случаев, когда это операнд операторов sizeof или унарных & или строковый литерал, используемый дляинициализировать массив символов в объявлении, выражение типа "массив N-элементов из T" будет преобразовано ("затухание") в выражение типа "указатель на T", изначением выражения будет адрес первого элемента массива.

Строковый литерал "1" представляет собой массив выражение типа char [2].В этом контексте он «затухает» до выражения типа char *, а значением выражения является адрес первого символа строки.Итак, вы присваиваете лайк:

 a = "l"; // char * = char *

Этого не происходит с целочисленным вариантом.Литерал 1 имеет тип int, но вы пытаетесь присвоить это значение int объекту int *:

a = 1; // int * = int 

, который должен вызвать диагностику.Вы можете назначить int * значение только для объекта int * - вам нужно явно привести 1:

a = (int *) 1; 

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

0 голосов
/ 24 сентября 2019

Суть этого:

Тип данных "1" равен char*.Таким образом, вы присваиваете char* переменной char*.

Тип данных 1 равен int.Таким образом, вы присваиваете int переменной int*, которая не будет работать, поскольку типы не совпадают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...