2016-12-09 3 views
0
int add(int a, int b) 
{ 
    return (int)&(((char *)a)[b]); 
} 

Почему я должен бросить a к char * и не int *?Сложение без использования знаком +

Я пытаюсь понять этот код полностью, но я не могу, поэтому, если вам легко, пожалуйста, предоставьте простое английское объяснение.

+0

Этот код не компилируется на GCC и Clang. – NathanOliver

+0

Откуда у вас этот код? – user463035818

+7

Лучшее в этом коде, которое вы можете сделать - выбросить его в мусор и больше не упоминать об этом. – Starl1ght

ответ

0

Почему я должен использовать a для char *, а не int *?

Чтобы прояснить для читателей вопроса, вы не предполагается использовать код, как это вообще. Но предположим, что вы конкурируете в ioccc (есть ли вариант C++ этого соревнования?), И в этом случае это может быть именно то, что вы должны делать.

Итак, чтобы ответить на вопрос, это потому, что арифметика указателя масштабируется по размеру заостренного объекта. Если вы использовали int*, тогда b будет масштабироваться sizeof(int). Поскольку вы не хотите масштабировать либо операнд сложения, вы масштабируете с 1 (мультипликативный идентификатор), который происходит, когда остроконечный тип имеет размер 1, который по определению char имеет.

P.S. Программа плохо сформирована и может не скомпилироваться на стандартных совместимых компиляторах.

+1

Нет ioC++ cc. В написании нечитаемого C++ не было бы проблем. –

+0

Спасибо за объяснение. Я не задавал этот вопрос из моего основного acc, потому что знал, что будет реакция. Но вы правы, это для конкуренции. –

+0

@Tracy Я думаю, что заявляя, что намерение состоит в том, чтобы написать обфускацию кода, и что это не для использования в производстве, возможно, смягчило реакцию. Не все читатели этого сайта поймут неявно. Некоторые из них (и люди, которые не хотят, чтобы такие люди путались), могут пожелать, чтобы это было проголосовано в забвении. – user2079303

6

Идея состоит в том, что массив представляет собой просто добавление указателя с индексом. Если a является char [] (или char *), а b является целым числом, то a[b] - это значение по адресу a+b. Этот код отличает a как указатель, индексирует его с помощью b и находит адрес, который должен равняться a+b.

Но в реальном мире никогда не делайте этого.

+0

... и код использует скрытый '+', а именно: 'a [b]' означает '* (a + b)'. –

+1

Итак? Первоначальный вопрос был «без использования знака +». Код не использует знак +. –

+0

@GraemePerrow, почему он добавляется? Я имею в виду, [b], например, 100 [103] == 100 + 103. –

0

Чтобы скомпилировать его, необходимо включить его в действительный C++. Указатели несовместимы с целыми числами, а расстояние между двумя указателями целочисленный тип:

#include <iterator> 

int add(int a, int b) 
{ 
    auto p = (char *)0; 
    auto p2 = &(&p[a])[b]; 

    return static_cast<int>(std::distance(p, p2)); 
} 

Отказ от ответственности: Я не поддерживаю этот продукт или услугу.

+0

FYI код в исходном вопросе компилируется (как C) и работает с Visual Studio 2013. –

+0

При вычислении 'p2' вы имеете выражение' p [a] '. Это неопределенное поведение, потому что 'p' является нулевым указателем. –

+0

@MartinBonner выражение '& p [a]' - После слияния c-стиля p не является нулевым указателем, это просто указатель на char. Является ли получение адреса p [a] UB или нет, я боюсь, что не знаю стандарта, достаточно глубоко, чтобы комментировать. –

0

Давайте возьмем пример с как 100 и б в 103

  1. (char *)a -> это приведения типов в качестве указателя. Таким образом, a будет считаться указателем.
  2. ((char *)a)[b] -> это 100 [103], то есть дает значение в месте (100 + 103)
  3. &(((char *)a)[b] -> это дает адрес указанного выше значения, т.е. она дает 203.
  4. (int)&(((char *)a)[b] -> конечный typecast to int преобразует адрес выше в целочисленное значение, как требуется возвращаемым значением функции.

Это будет работать только с char* приведения типов в шаге 2. Если вы используете int* приведение типа там, сумму, которую вы получите в шаге 3 будет 100 + 4*103 т.е.512

+2

«это 100 [103]» должно быть «это неопределенное поведение». – Lundin

+0

'a' является указателем на этом этапе. поэтому 'a [b]' четко определен. –

+0

Ришикеш, пожалуйста, будьте немного точнее. В пункте 2 значение никогда не принимается (будет segfault); в пункте 4 нет «значения char», просто адреса. –

Смежные вопросы