Выполняют ли спецификаторы формата неявное преобразование типов?

#include <stdio.h>

int main(void) {
    int x = 5;
    int y = &x;

    printf("Signed Value of Y: %d \n", y);
    printf("Unsigned Value of Y: %u", y);

    return 0;
}

Поскольку y имеет тип int, использование %d дает вывод, возможно, со знаком, тогда как %u дает вывод без знака. Но y имеет тип int, так почему же %u выдает беззнаковый вывод? Существует ли неявное преобразование типов?

Просто сказал: нет. Вы должны убедиться, что тип совпадает.

LHLaurini 12.01.2023 16:33

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

phuclv 12.01.2023 16:35

Спецификаторы формата вообще не выполняют преобразования. Они говорят printf как интерпретировать значение внутри.

Eugene Sh. 12.01.2023 16:35

Да, но это связано с тем, как вариативные функции обрабатывают параметры, а не спецификаторы формата. Например, если вы передадите char, оно будет преобразовано в int, float в double и т. д.

0___________ 12.01.2023 16:40

@EugeneSh.: Re «Спецификаторы формата вообще не выполняют преобразования»: Да, насчет этого, они на самом деле называются спецификациями преобразования. Потому что они определяют, как «аргументы преобразуются для вывода» (C 2018 7.21.6.1 2).

Eric Postpischil 12.01.2023 16:42

параметры подвергаются продвижению аргументов по умолчанию. Читать port70.net/~nsz/c/c11/n1570.html#6.5.2.2p6

tstanisl 12.01.2023 16:49

@EricPostpischil Это не «преобразования типов», о которых спрашивает ОП. Должно быть ясно из контекста.

Eugene Sh. 12.01.2023 16:50

@EugeneSh.: Re «Должно быть ясно из контекста»: вы не можете ожидать, что люди, которые задают вопросы, потому что они ничего не знают, будут знать что-то из контекста.

Eric Postpischil 12.01.2023 16:52

Функция printf понятия не имеет, какой тип переменной вы ей передали. Он полагает, что вы передали обещанный тип (используя этот спецификатор), и какие бы данные вы ни передали, printf попытается вывести их, как если бы найденный шаблон битов был типом, который вы обещали.

Weather Vane 12.01.2023 17:06
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
87
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Существует ли неявное преобразование типов?

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

Спецификация языка C явно отказывается говорить, что происходит, когда типы аргументов printf не соответствуют должным образом спецификациям преобразования в прилагаемой строке формата. На практике, однако, некоторые пары типов данных имеют представления, достаточно похожие друг на друга, так что попытка printf() интерпретировать данные одного типа, как если бы они были другого типа, с большой вероятностью (но не обязательно) создаст видимость неявного преобразования. от одного вида к другому. Такими парами обычно являются соответствующие целочисленные типы со знаком и без знака.

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

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

По сути, вызов printf — это две разные вещи:

  • Все аргументы подготовлены для отправки в функцию.
  • Функция интерпретирует строку формата и другие ее аргументы.

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

В вызове функции правила в основном (опуская некоторые детали):

  • Если аргумент соответствует объявленному типу параметра, он преобразуется в этот тип.
  • В противном случае (если аргумент соответствует части ... объявления функции или вызываемая функция объявлена ​​без указания типов параметров), применяются некоторые акции по умолчанию. Для целых чисел это целочисленные продвижения, которые в значительной степени (опуская некоторые детали) преобразуют типы более узкие, чем int, в int. Для чисел с плавающей запятой float превращается в double.

printf объявлен как int printf(const char * restrict format, ...);, поэтому все его аргументы, кроме строки формата, соответствуют ....

Внутри printf функция проверяет свою строку формата и пытается выполнить директивы, указанные в строке формата. Например, если директива %g, printf ожидает аргумент double и берет биты из того места, где ожидается передача аргумента double. Затем он интерпретирует эти биты как double, создает строку в соответствии с директивой и записывает строку в стандартный вывод.

Для директивы %d или %uprintf ожидает аргумент int или unsigned int соответственно. В любом случае он берет биты из того места, где ожидает передачи аргумента int или unsigned int. Во всех известных мне реализациях C аргументы int и unsigned int передаются в одном и том же месте. Итак, если вы передадите аргумент int, но используете %u, printf получит биты int, но будет обрабатывать их так, как если бы они были битами unsigned int. Фактическое преобразование не было выполнено; printf просто по-разному интерпретирует биты.

Стандарт C не определяет поведение, когда вы делаете это, и реализация C будет соответствовать стандарту, если произойдет сбой, когда вы это сделаете, или если она обработает биты по-другому. Вам следует избегать этого.

«Re: Но y имеет тип int, так почему же %u выдает беззнаковый вывод?»


Из С11:

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

где,

undefined — Поведение для чего-то неправильного, на котором Стандарт не предъявляет никаких требований. Всё позволено случиться, из ничего, к предупреждающему сообщению о завершении программы, к расплавление процессора, запуск ядерных ракет (при условии, что у вас есть установлена ​​правильная аппаратная опция).

— Экспертное программирование на C.

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