На практике компилятор должен знать, какой тип возвращает функция, потому что ему нужно знать, как интерпретировать биты, возвращаемые функцией, и ему нужно знать, где эти биты.
Предположим, что когда функция возвращает, регистр, используемый для возвращаемого значения, содержит 0x80. Если функция должна возвращать 8-битное unsigned char
, то возвращаемое значение - 128. Если функция должна возвращать 8-битное дополнение до двух signed char
, то возвращаемое значение - -128. Знание типа необходимо для понимания интерпретации битов.
Во многих системах функция, возвращающая целое число, должна помещать биты в определенный общий регистр процессора, но функция, возвращающая значение с плавающей запятой, должна помещать биты в определенный регистр с плавающей запятой . В этом случае вызывающей стороне необходимо знать тип возвращаемого значения функции, чтобы знать, где находятся биты возвращаемого значения.
На более абстрактном уровне компилятору необходимо знать тип возвращаемого значения функция, чтобы она могла интерпретировать выражение, в котором появляется вызов функции. Учтите, что в C выражение 5 / 4
выполняет целочисленное деление с усечением и дает 1, а выражение 5. / 4
выполняет деление с плавающей запятой и дает 1,25 . Итак, в выражении f(x) / 4
компилятор должен знать, какой тип f
возвращает, чтобы он знал, выполнять ли целочисленное деление или деление с плавающей запятой.
Для другого примера предположим, что f
возвращает указатель, и программа использует y = *f(x)
. Чтобы выполнить этот код, компилятор должен взять значение, возвращаемое f
, и использовать его как адрес для извлечения чего-либо из памяти. Но что он приносит? Указывает ли адрес на однобайтовую char
, восьмибайтовую double
или 100-байтовую структуру? Компилятору необходимо знать тип указателя, возвращаемого f
, чтобы он знал, на какой тип объекта он указывает.
Из этого небольшого тестового кода кажется, что реальная цель записи int
в качестве типа данных возвращаемого значения demo_function
- это приведение типов .
Основная цель описана выше. Тот факт, что значение в операторе return
преобразуется в тип возвращаемого значения функции, является вторичным эффектом; это просто удобство языка, а не необходимый эффект. (В неявном преобразовании нет необходимости, потому что мы могли бы повлиять на преобразование, указав его явно.)
Также обратите внимание, что cast является явным оператором. Это не операция. Например, +
и *
- операторы; это вещи, которые появляются в исходном коде и говорят, что мы хотим выполнить определенные операции. Фактические операции - это сложение и умножение. Точно так же приведение - это имя типа в круглых скобках; это некоторый текст, который появляется в исходном коде, который указывает, что мы хотим выполнить преобразование.