Как отмечено в комментариях, определение макроса, которое вы представляете, не расширяется до действительного кода C, поскольку оно включает вычисление (char*)0 % sizeof(long)
, где левый операнд %
имеет тип char *
. Это не целочисленный тип, но оба операнда %
должны иметь целочисленный тип.
Кроме того, расширение макроса имеет несбалансированные круглые скобки. Это не является по сути неправильным, но делает этот макрос сложным в использовании. Кроме того, даже там, где приоритет оператора дает разумный результат, использование скобок и дополнительных пробелов может помочь человеку интерпретировать код без ущерба для скорости выполнения и незначительных дополнительных затрат на компиляцию.
Итак, я думаю, что желаемый макрос будет примерно таким:
#define SWAPINT(a,es) swaptype = ( \
((((char*)a - (char*)0) % sizeof(long)) || (es % sizeof(long))) \
? 2 \
: ((es == sizeof(long)) ? 0 : 1)) \
)
Вместо этого я бы предпочел написать предпоследнюю строку как
: (es != sizeof(long))
чтобы уменьшить сложность выражения за счет небольшой потери его понятности. В любом случае намерение состоит в том, чтобы установить swaptype
на:
2
, если a
не выровнено по границе n
байт, где n
— количество байтов в long
, или если es
не является целым числом, кратным размеру long
; в противном случае
1
, если es
не равно размеру long
; в противном случае
0
Это похоже, но не идентично вашей интерпретации. Обратите внимание, однако, что даже этот код имеет неопределенное поведение из-за (char*)a - (char*)0
. Оценка этой разницы определила поведение только в том случае, если оба указателя указывают на один и тот же объект или сразу за его концом, а (char *)0
не указывает (в) на конец какого-либо объекта или сразу за его концом.
Вы спросили конкретно:
Но я не понимаю, зачем реализовано преобразование типов, (char*)a.
Это выполняется, потому что арифметика указателя определяется в терминах типа, на который указывает указатель, поэтому (1) соответствующая программа не может выполнять арифметику с void *
, и (2) код хочет, чтобы результат вычитания был в тех же единицах. как результат оператора sizeof
(байт).
И что значит эта строка?
(char*)a- (char*)0)% sizeof(long)==1
Эта строка не появляется в макросе, который вы представили, и это не полное выражение из-за несбалансированных скобок. Похоже, он пытается определить, указывает ли a
на единицу за границей n
байт, где n
определено выше, но опять же, оценка разницы указателей имеет неопределенное поведение. Также обратите внимание, что для целого числа x
значение x % sizeof(long) == 1
, оцениваемое в логическом контексте, имеет другое значение, чем x % sizeof(long)
, оцениваемое в том же контексте. Последнее имеет больше смысла в контексте, который вы описали.
person
John Bollinger
schedule
03.10.2016
(char*)0 % sizeof(long)
даже не имеет смысла, потому что тип указателя не является арифметическим типом. Что бы это ни было, это не соответствует C. Где вы нашли этот код? А вы уверены, что правильно скопировали? - person   schedule 03.10.2016%
лучше-
, поэтому(char*)a- (char*)0 % sizeof(long)
равно(char*)a - ((char*)0 % sizeof(long))
. Конечно,((char*)a- (char*)0) % sizeof(long)
хотелось. - person chux - Reinstate Monica   schedule 03.10.2016==1
в вашей интерпретации должно быть!=0
. Также отсутствует)
после(char*)0
в вашем макросеSWAPINT
, что приводит к несбалансированным скобкам. МакросSWAPINT
, по-видимому, устанавливаетswaptype = 2
, еслиa
не выровнено (по границеsizeof(long)
байтов) илиes
не кратноsizeof(long)
, устанавливаетswaptype = 0
, еслиa
выровнено, аes
равно точноsizeof(long)
, или устанавливаетswaptype = 1
, еслиa
выровнено, аes
является целым числом. несколько != 1 изsizeof(long)
. - person Ian Abbott   schedule 03.10.2016((char*)a - (char*)0)
преобразует a в целочисленное значение типаptrdiff_t
без явного приведения. Он не является переносимым, но поскольку он является частью реализации стандартной библиотеки для платформы, он не должен быть переносимым. - person Ian Abbott   schedule 03.10.2016