2012-04-28 3 views
2

Я работаю с некоторыми последовательными связями в C в Linux. Я делаю это, используя дескрипторы файлов. По какой-то причине после char* s = "Hello world" я могу написать s на последовательный порт, используя метод записи, без проблем. Я использую программу последовательного мониторинга для проверки другого конца. Однако я не могу отправить другие данные. Я получаю ошибку «Плохой адрес» из функции записи.Целочисленные указатели в C?

Тем не менее, я заметил, что если бы я сделал что-то очень странное: int* x = "5"; Что я мог тогда послать это x. Мой вопрос: что в мире делает int* x = "5" означает?

+2

'int * x =" 5 "' объявляет 'x' как указатель на целое число, которое находится в начале строки' '5" '. Когда вы его пишете, он, вероятно, печатает символ «5», нулевой символ и любые последующие два байта, предполагая 'sizeof (int) = 4' на вашей платформе. –

+3

@ AdamLiss no, он сказал «5» не 5. –

+0

@SethCarnegie Нет, он сказал '5', а затем отредактировал свой вопрос, чтобы сказать« 5 », а затем я обновил свой комментарий. :-) –

ответ

0

int* x = "5" неявно ставит "5"const char*) к int* и сохраняет его в x. Таким образом, x будет указывать на sizeof(int) байтов, в которых самый низкий - 0x35 (символ «5»), а следующий - 0, а остальные неопределены и приведут к неопределенному поведению при чтении.

+0

Не говоря уже о том, что он использует crappy-компилятор, который позволяет 'char const [2]' быть неявно конвертируемой в 'int *' –

+3

Собственно, '' 5 "' является 'char []', а не 'const char *', даже если вы должны использовать его, как будто это 'const'. –

+1

Он, вероятно, использует дерьмовый компилятор, который позволяет 'char *' быть неявно конвертируемой в 'int *'; выражение '' 5 "' распадается на 'char *' в большинстве контекстов. –

3
int* x = "5"; 

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

int *x = (int *) "5"; 

В этом последнем коде хранится объект без названия типа char [2]. Значение "5" является указателем на его первый элемент, указатель - char *. Литье преобразует char * в int * и сохраняет его в x.

+0

не разрешено ли «char *» на что-нибудь? (в соответствии с правилами сглаживания С) – moooeeeep

+0

@moooeeeep не существует нарушения сглаживания, но указатели могут не иметь одинаковых требований к выравниванию. – ouah

2
int* x = "5"; 

является нарушениемограничения. Это означает, что любой соответствующий компилятор должен выдать ему диагностику. Это не должно рассматриваться как фатальная ошибка; компилятору разрешено выпустить предупреждение, а затем успешно перевести программу. Но язык не определяет поведение этого объявления.

Существует неявное преобразование от char* (тип "5" после его распадов) до int*.

Это как можно ближе к C, чтобы сказать, что что-то незаконно.

На практике, компиляторы, которые принимают это заявление, скорее всего, относиться к нему как эквивалент:

int *x = (int*)"5"; 

т.е. они будут вставлять преобразование. (Это не единственная возможная интерпретация, но большинство компиляторов либо интерпретирует ее так, либо отклонит ее.) Это принимает значение char*, которое является результатом распада выражения массива "5" (то есть, адрес символа '5' на начало строки) и преобразуется в int*.

В результате указатель int* указывает на объект int, который может быть или недействителен. Строка "5" имеет длину 2 байта ({ '5', '\0' }). Если int - это два байта, то *x может оценивать результат интерпретации этих двух байтов как значение int, что будет зависеть от его сущности. Или, если строковый литерал неправильно выровнен для объекта int, оценка *x может привести к прекращению вашей программы.И если int шире, чем два байта (как это обычно бывает), *x относится к памяти за конец строкового литерала. В любом случае попытка изменить *x имеет еще один вид неопределенного поведения, поскольку попытка изменить строковый литерал явно не определена.

При составлении этой декларации вы должны получить хотя бы предупреждение. Если это так, вы определенно не должны были его игнорировать. Если вы не получили предупреждение, вы должны узнать, как уговорить ваш компилятор для получения дополнительных предупреждений.

TL; DR: Не делайте этого.

+0

Ничего себе спасибо. Да, я действительно не ожидал, что это скомпилируется, и когда это произойдет, я был полностью смущен. Мне просто интересно, что это на самом деле означает. Благодаря! – Pha3drus

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