Семантические различия в Алголе и С в кастинге
Предположим, у нас есть следующие инструкции в Алголе 68 и С, соответственно:ref int x := 5;
а также (int*) x = 5;
, В чем их семантическая разница?, это то же самое?, потому что я думаю, что второй говорит что-то вроде "х будет указывать на константу" (это не может быть скомпилировано), а первый говорит "х будет указывать на память ячейка, которая указывает на другую ячейку памяти, которая содержит константу 5". Это правильно? Если нет, можете ли вы объяснить это немного и привести несколько примеров, чтобы понять это?
2 ответа
Я не претендую на звание эксперта по Алголу-68 (или Алгол-60) - я никогда не собирал ничего на одном языке.
Тем не менее, Википедия о декларации режима Algol 68 гласит:
Тем не менее, декларация
real x;
это просто синтаксический сахар дляref real x = loc real;
, То есть,x
действительно постоянный идентификатор для ссылки на недавно сгенерированный локальныйreal
переменная.
Учитывая это объяснение, фрагмент Алгола вопроса:
ref int x := 5;
соответствует (более или менее) коду C:
int *x = malloc(sizeof(*x));
*x = 5;
оставляя в стороне вопросы проверки ошибок и освобождения выделенной памяти.
Фрагмент вопроса C:
(int *)x = 5;
в значительной степени бессмысленно - результат приведения не является изменяемым lvalue, и вы можете назначить только изменяемое lvalue. Если переписано как:
int x_data;
int *x = &x_data;
*(int *)x = 5;
тогда это становится действительным C, хотя приведение полностью излишне. Конечно, можно было бы также использовать распределение памяти. В C любое использование x
для доступа к целочисленному значению (в отличие от указателя) требуется разыменование в C (*x
или же x[0]
). В отличие от этого, в Алголе 68 нет необходимости явно разыменовывать переменную x
,
Хотя вопрос упоминает "константу" пару раз, я не вижу ничего, что подразумевало бы постоянство в коде. Значение 5
присваивается переменной в местоположении. Значение, сохраненное в местоположении, может быть изменено позже другим назначением.
Заголовок вопроса спрашивает о приведении, но я не вижу доказательств приведения в коде Algol, и неясно, почему приведение считается необходимым в C-коде.
В Algol 68 доступно много неявных принуждений, зависящих от контекста (сильный, твердый, кроткий, слабый и мягкий контекст): см. Википедия и иерархия приведения Algol68.
Algol68 может неявно обрабатывать:
- увеличение точности и размеров (Сильный)
- объединяющий разные типы (фирма)
- целевая разыменование (как кроткая, так и слабая)
- процедура, депроцедура (Soft)
C casting имеет более ограниченное неявное приведение:
- ограничивается неявным "расширением" точности и
float
вint
только в некоторых случаях. Расширение до массивов требует указателей и ручного кодирования с использованием оператора "&". - Союзы должны быть закодированы / созданы вручную.
- Нет разыменования во время приведения (C вынуждает кодера явно определять, сколько раз разыменовывать указатель, используя оператор "*").
- Процедура без аргументов должна быть явно определена по имени и вызываться с использованием оператора "()".
Пример кода с выводом...
Файл: deref_and_cast.c
#include <stdio.h>
#include <stdlib.h>
main(){
auto int*** crrri;
crrri=(int***)malloc(sizeof(int**));
*crrri=(int**)malloc(sizeof(int*));
**crrri=(int*)malloc(sizeof(int));
***crrri=255; /* coder to explicitly work out how many times dereference */
printf("%5.1f\n",(float)***crrri); /* Again deref is muilt-explicit */
}
Выход:
255.0
Файл: coerce_and_cast.a68
#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
LOC REF REF REF INT crrri;
REF REF REF REF INT(crrri):=HEAP REF REF INT;
REF REF REF INT(crrri):=HEAP REF INT;
REF REF INT(crrri):=HEAP INT;
REF INT(crrri):=255; # targeted dereferencing (3x) depending on contect #
printf(($"example meek coercion:"g(-5,1)l$,REAL(crrri)));
Примеры Иерархии неявных принуждений
PROC VOID raise exception = end; # Implicitly cast a "GO TO" to a PROC #
# Soft: deprocedure a PROC to a VALUE #
printf(($"Soft:"gl$,random)); # Implicit Coercion #
printf(($"Soft:"gl$,REAL(random))); # Explicitly cast/deprocedure #
# Weak: dereference pointer chain to a "name" (LHS in C lingo) #
COMPL compl:= 0;
re OF compl := crrri; # Implicit Coercion #
REF REAL(re OF compl) := crrri; # Explicitly cast/dereference #
printf(($"Weak:"g(-0,4)g(7,4)"i"l$,compl));
# Meek: dereference to a value #
printf(($"Meek:"gl$,sin(crrri))); # Implicit Coercion #
printf(($"Meek:"gl$,sin(REAL(crrri)))); # Explicitly cast/dereference #
# Firm: unite to a UNION #
MODE IRC=UNION(INT,REAL,COMPL);
OP SIN = (IRC z)IRC: (z|(INT i):sin(i),(REAL r):sin(r),(COMPL z):complex sin(z));
printf(($"Firm:"gl$,SIN 1)); # Implicit Coercion #
printf(($"Firm:"gl$,SIN IRC(1))); # Explicitly cast/unite #
# Strong: widen to higher precision OR to an array #
FLEX [0]BOOL bool array := BIN crrri; # Implicit Coercion #
bool array := []BOOL(BIN crrri); # Explicitly cast/widen #
printf(($"Strong:"$,$g$,bool array,$l$));
end: SKIP
Выход:
example meek coercion:255.0
Soft:+2.11679610884246e -1
Soft:+4.01945464342605e -1
Weak:255.0000+0.0000i
Meek:-5.06391634924491e -1
Meek:-5.06391634924491e -1
Firm:+8.41470984807897e -1
Firm:+8.41470984807897e -1
Strong:FFFFFFFFFFFFFFFFFFFFFFFFTTTTTTTT
Алгол68 строго подходил к значению "имени" (что не то же самое, что "идентификатор"). Одним из видимых результатов этого является то, что Algol68 имеет тенденцию иметь еще один ref в типе / режиме объекта, чем в других языках.
таким образом INT
является режимом постоянного целого числа (которому может даже не потребоваться выделение памяти во время выполнения). REF INT
режим "целочисленной переменной", и REF REF INT
является режимом "ссылки на целочисленную переменную".
INT x = 42;
REF INT y = LOC INT := x;
REF REF INT z = LOC REF INT := y;
LOC - это "локальный генератор", который, по сути, просто выделяет пространство стека и возвращает его "имя" (он же адрес).
(Обратите внимание, что '=' устанавливает эквивалентность, а ':=' присваивает значение)
Желательный знакомый синтаксис означал, что в двух объявлениях переменных могут использоваться сокращенные формы:
INT y := x;
REF INT z := y;
но режим y
все еще REF INT
и т. д. ИМО, эта аббревиатура была плохой идеей.
С эквивалентность:
#define x 42
int y = x;
int* z = &y;