2012-06-03 2 views
0

я видел эту сложную декларацию SizeOf оператора где-то в книге, которая дразнила меня:комплексов Декларации оператора SizeOf в С

#define SIZEOF(int) (int)&((int *)0)[1] 

Может ли один объяснить это заявление, что происходит здесь ...?

+15

Пожалуйста, укажите имя/автора книги, чтобы другие могли избежать этого. –

+1

напоминает мне о том, что я нашел в этой книге: http://www.amazon.com/The-Puzzle-Book-Alan-Feuer/dp/0201604612/ref=la_B001IXRU2O_1_1?ie=UTF8&qid=1338723178&sr=1-1 – Levon

+2

Зачем отмечен как C++? – iammilind

ответ

6

Здесь с [1] части «расширена»:

(int)(&(*(((int*)0) + 1))) 

Теперь вы видите, как это работает?

0 увеличится на sizeofint из-за свойства арифметиков указателей и окончательного int броска получает вам значение результирующего адреса, который является «размером».

Это совершенно неопределенное поведение, хотя (арифметика на null и, возможно, разыменование недействительного указателя), довольно бессмысленно.


Обновление с параметром макроса не имеет большого смысла. Окончательный отбор должен, вероятно, быть std::uintptr_t.

+3

+1 для указания неопределенного поведения. –

+0

Обратите внимание, что 'int' - это параметр макроса –

+0

-1: Преобразование' [] 'в' * (x + y) 'не является частью« расширения », запутанное здесь, поскольку оно связано с макросами, вам нужно предоставить аргументы развернуть макрос, и бесполезно говорить «UB» без объяснения причин. В этом случае единственным источником неквалифицированного UB является интегральное переполнение, что не имеет значения. – Potatoswatter

4

Во-первых - это путают вещи с термином int - мы, естественно, считаем, что это ключевое слово знакомого типа, однако в данном случае это не так - вместо этого это аргумент макроса. Поэтому для упрощения рассмотрят макрос следующим образом:

#define SIZEOF(type) &((type *)0)[1] 

Теперь, глядя на него таким образом, это, возможно, легче увидеть, что макрос первого адрес отливки 0 быть указателем на type, а затем он принимает адрес второго элемента. Это покажет размер.

+0

Приятно, что вы заметили запутанное имя аргумента! –

+0

+1 для указания запутанного использования 'int' в качестве параметра макроса - другие ответы, опубликованные до сих пор, не обнаружили этого –

1

Он определяет SIZEOF как размер целого числа.

  • (int *)0 является указателем INT по адресу нулевого
  • [1]получает доступ к следующей целого числа после того.
  • С (int *)0 имеет нулевой адрес, после того, как он имеет адрес sizeof int, поскольку он поступает сразу после предыдущего.
  • (int) отдает его числу, так как размер является числом, а не указателем.

Очевидно, что это неприятный взлом, нужно просто использовать sizeof int.

+0

. Обратите внимание, что' int' является макропараметром –

+0

Только после того, как OP отредактировал свой вопрос , – ThiefMaster

+0

@ThiefMaster предварительная запись была '#define SIZEOF (int) & ((int *) 0) [1]'. Я считаю, что в этом случае «int» все еще является макропараметром, но интервал между линиями делает его менее очевидным. Правильно ли, или есть какое-то специальное правило относительно интервала в макроопределениях? – mah