Что происходит при использовании 'vs' в C?

Кто-то поднял этот код до меня, что заставило меня задуматься, что там происходит код выглядит следующим образом из VS 2019:

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

int main()
{
    char y = '5';
    char w = "5";
    printf("size of x %x\n",&w);
    printf("size of X %X\n", w);
    printf("size of X in number: %d \n", w);
    printf("size of Y %d\n\n", w);

    w = '5';
    printf("size of y %x\n", &w);
    printf("size of Y %X\n", w);
    printf("size of X in number: %d \n", w);
    printf("size of Y %d\n\n", w);

    return 0;
}

Вывод выглядит следующим образом:

size of x 8ff8bb
size of X 30
size of X in number: 48
size of Y 48

size of y 8ff8bb
size of Y 35
size of X in number: 53
size of Y 53

Интересно, что там происходит на самом деле? кто-то указал, что 'является символом, а "является строкой, но если это так, почему здесь можно поместить строку в символ, и почему это результаты?

Спасибо за ответы Я понимаю, что это может быть не слишком актуально для использования, но мне интересно, что там происходит, я только недавно вернулся, чтобы переучить C

Код скомпилирован и не выдает предупреждений в VS2019.

Поиск Google в основном дает мне результаты о том, как помещать символы в массив и тому подобное, не смог найти никакой информации об этом поведении.

"size of x %x\n",&w - За исключением того, что он не печатает размер, поскольку &w не является размером чего-либо.
StoryTeller - Unslander Monica 10.04.2019 16:06

Это ничего не может вывести, так как это не компилируется.

Quentin 10.04.2019 16:07

Этот код не имеет никакого смысла по отношению к тексту, который он печатает.

klutt 10.04.2019 16:07

Я должен был отредактировать его, опубликовать код, как он был дан

Black Blade 10.04.2019 16:08
char w = "5"; выдаст предупреждение и, скорее всего, не сделает то, что вы думаете.
klutt 10.04.2019 16:09

Я знаю, что это то, что должно произойти (не компилировать), но, как кажется, VS, по крайней мере, компилирует его. Теперь я заметил, что поставил VSCode .. мой плохой, имел в виду VS не код

Black Blade 10.04.2019 16:10

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

klutt 10.04.2019 16:12

Выходной текст, похоже, не имеет никакого отношения к печатаемым значениям. Например, последние два printf в каждой группе, очевидно, печатают одно и то же число, но имеют разный текст.

Arkku 10.04.2019 16:12

Когда программа бессмысленна, нет смысла пытаться понять, что она делает.

Christian Gibbons 10.04.2019 16:13

Правильное исправление действительно выдает предупреждение, но не при вводе строки в char, а в printf

Black Blade 10.04.2019 16:13

Почему вы сделали свой вывод таким запутанным? Вы печатаете «размер X», чтобы показать значение w. Почему ты так усложняешь? Кого ты пытаешься запутать?

Jonathan Wood 10.04.2019 16:14

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

Black Blade 10.04.2019 16:15

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

klutt 10.04.2019 16:15
char w = "5"; определяет строковый литерал "5" и присваивает его адрес (где находится символ '5') переменной char w, усекая значение указателя до char. Выходное значение 0x30 (шестнадцатеричное) или 48 (десятичное), вероятно, означает, что это значение имеет младший байт адреса строкового литерала.
Bodo 10.04.2019 16:16

@JonathanWood Его код отправлен мне, сохраните его в исходном коде, имена, которые я предполагаю, сделаны для тестирования кода, не утруждая себя внесением изменений в печатную информацию.

Black Blade 10.04.2019 16:16

@Bodo Я не уверен, что это правда, что значение указателя усекается. Если char является подписанным типом, то он должен переполняться, что, как мне кажется, приводит к неопределенному поведению.

Christian Gibbons 10.04.2019 16:17

@ChristianGibbons Неопределенное поведение не означает, что оно не усекается. Он может делать все что угодно, в том числе и оборачиваться.

Arkku 10.04.2019 16:22

@Arkku Я не хотел, чтобы это не могло привести к переносу, а скорее к тому, что ожидать усечения ненадежно (если только вы не знаете, что работаете в системе, где char не имеет знака). Таким образом, пытаться понять это бессмысленно.

Christian Gibbons 10.04.2019 16:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
19
174
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Строка представляет собой массив символов, оканчивающихся символом NUL. Данные здесь:

"5"

Это то же самое, что:

{'5','\0'}

Когда вы присваиваете значение массива чему-то в C, вы назначаете указатель на первый элемент в массиве. Итак, когда вы пишете:

char w = "5"

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

Делая это:

printf("size of x %x\n",&w);

Распечатывает местоположение w в памяти

Делая это:

printf("size of X %X\n", w);

печатает значение w, в вашем случае было присвоено адресу массива строк и усечено, потому что char не может соответствовать адресу.

Если вы хотите использовать строку, вы должны сделать это:

const char * w = "5"

Затем вы можете распечатать строку следующим образом:

printf("string: %s\r\n", w);

вы можете распечатать первый символ в массиве одним из этих способов

printf("char: %c\r\n", *w);
printf("char: %c\r\n", w[0]);

Для второго бита, когда вы назначаете w следующим образом:

char w = '5';

печать &w печатает местоположение в памяти.

печать w с %x печатает значение ASCII '5', которое равно 0x35

Спасибо за ответ, думаю, это действительно просто усечено, тогда

Black Blade 10.04.2019 16:49

Инициализация

char w = "5";

делает две вещи:

  • Определите символьный литерал "5", который представляет собой некоторую область памяти, содержащую '5', за которой следует NUL ('\0').
  • Определите переменную w типа char и инициализируйте ее адресом строкового литерала, то есть адресом памяти, где находится '5'. Адрес (указатель) преобразуется в char, что приведет к потере части значения, поскольку char обычно меньше указателя (char*).

С участием

printf("size of X %X\n", w);

вы печатаете значение char w в шестнадцатеричной форме, которое, вероятно, является младшим значащим байтом адреса строкового литерала.

Вам лучше использовать

printf("size of X %X\n", (unsigned int)w); /* %X = unsigned int */

или

printf("size of X %hhX\n", w); /* %hhX = unsigned char or signed char */

чтобы формат соответствовал типу аргумента.

Даже если это не изменит результат в вашем случае, это гарантирует, что код printf не получит доступ к памяти, которая возможно неинициализирована или может содержать несвязанные данные.

Когда я запустил ваш код, в одном случае значением w было 0xA8, которое было напечатано как FFFFFFA8. В этом случае %hhX напечатает только A8.

Я не уверен, что именно произойдет, когда вы передадите значение char функции printf, в то время как формат указывает функции интерпретировать данные как unsigned int. Это может зависеть от соглашений о вызовах вашей платформы и реализации компилятора. Возможно, на вашей платформе все аргументы более коротких типов данных преобразуются в int или unsigned int.

Выполнение printf("size of X %hhX\n", w); и printf("size of X %X\n", (unsigned int)w); дает тот же результат, что и раньше. Спасибо за ответ.

Black Blade 10.04.2019 16:49

Другие вопросы по теме