C/C++ сила двух макросов

Я не так хорош со своими способностями двойки, как должен был бы, поэтому я подумал, что, может быть, я мог бы #define кое-что.

К сожалению, я очень неопытен, когда дело доходит до директив препроцессора, и я не мог понять, как делать такие вещи, как циклы for. Я посмотрел на:

Но ни в одном из них нет примеров циклов for. Все, что я хочу, это иметь возможность написать что-то вроде pwrtwo(5) вместо того, чтобы использовать калькулятор, чтобы вычислить, что 25 равно 32.


person Ace shinigami    schedule 10.03.2016    source источник


Ответы (4)


Почему бы не сделать это правильно и не использовать функцию? Это даже позволяет нам генерировать результат во время компиляции, используя мощный constexpr!

template <class T>
constexpr T pwrtwo(T exponent) {
    return (T(1) << exponent);
}
person Jan Nils Ferner    schedule 10.03.2016
comment
Вы даже можете создать шаблон, чтобы использовать его и для других целочисленных типов. - person mindriot; 10.03.2016
comment
Вернуть T, а не int? - person Humam Helfawi; 10.03.2016
comment
Вот кое-что, в чем я не уверен: лучше ли писать T(1), или выражение все равно получает тип правой части? То есть, правильно ли это работает, если T больше, чем int (тип 1)? - person mindriot; 10.03.2016
comment
@mindriot Приведение происходит неявно, но я добавил его в ответ, потому что явные приведения всегда предпочтительнее. - person Jan Nils Ferner; 10.03.2016
comment
Только что проверил. Вам обязательно нужно явное приведение типов: ideone.com/z5GGvS — даже в 64-битных системах это необходимо, потому что 1 по умолчанию интерпретируется как целое число со знаком. - person mindriot; 10.03.2016
comment
@mindriot интересно, кажется, я недостаточно хорошо его протестировал. Молодец, что вызвал меня! - person Jan Nils Ferner; 10.03.2016
comment
это компрометирует скорость? Я совершенно уверен, что этот метод не начнет работать до времени компиляции. - person Ace shinigami; 10.03.2016
comment
@ Джулиан, что ты имеешь в виду под не начинает работать до времени компиляции? Моя функция генерирует результат непосредственно в код скомпилированного кода. Это приложение точно такое же, как и любое #define, которое вы бы сделали, оно просто работает быстрее И в более общем плане в фоновом режиме, потому что это constexpr и шаблон. - person Jan Nils Ferner; 10.03.2016

Один ответ (неправильный) предполагает, что ответ должен быть #define pwrtwo(x) (1 << ((x) - 1). Однако:

1 = 0000 0001 в двоичном режиме

Теперь, когда его просят 2 в степени 5, тогда

1 ‹‹ (5-1) ; где х = 5

1 нужно сдвинуть 4 раза, тогда результат будет

0001 0000 ==> 2 мощность 4

Но это неправильно, и поэтому фактический ответ должен быть таким:

#define pwrtwo(x) (1 << (x))
person Nishant Bijani A    schedule 10.03.2016

2x равно 1 << x, поэтому:

#define pwrtwo(x) (1 << (x))
person user207421    schedule 10.03.2016
comment
это 1<<x не так ли? - person PeterT; 10.03.2016
comment
Хорошо, это был долгий день. Спасибо за исправления и правки. - person user207421; 10.03.2016

Этот макрос сделает работу:

#ifndef PWRTWO
#define PWRTWO(EXP) (1 << (EXP))
#endif

Однако было бы желательно не использовать его, если вы не ограничиваете или не ограничиваете диапазон значений, которые EXPможет быть!

Попробуйте ввести эти значения в этот макрос на машине, где размер int составляет 4 байта по одному, попробуйте скомпилировать и запустить, а затем скажите мне, что происходит при каждом значении:

std::cout << PWRTWO(30) << std::endl; // Okay
std::cout << PWRTWO(31) << std::endl; // - value

// In the following cout statement within the macro, do not confuse the 
// (x >= 32) as what is actually being passed into the macro as an argument. 
// This is just a short hand notation to represent all values >= 32 where the actual
// numerical value would be entered into this macro statement as there is
// no defined variable x here in this context nor any comparison expression being passed to it.

// Compiler Warning C4293 '<<' shift count negative or two big, undefined behavoir
std::cout << PWRTWO(X >= 32) << std::endl; // In most cases on my machine it prints out 0. 
//However, since this is undefined behavior, there is no telling what it could or may do on another machine.

ИЗМЕНИТЬ

// Try this for loop to see the actual values being printed out as long as 
// the integer value on your machine is 32bit or 4 bytes in size.
std::cout << "Excepted values for 32bit integers" << std::endl;
std::cout << "----------------------------------\n";
for ( int i = 0; i < 31; i++ ) {
    std::cout << PWRTWO( i ) << std::endl;
}
std::cout << std::endl;

// Then print out the next one
std::cout << "First value to produce a negative result with int being 32bit." << std::endl;
std::cout << "------------------------------------------\n";
std::cout << PWRTWO( 31 ) << std::endl << std::endl;

// Then print out these as well : compiler warnings
std::cout << "Value Range that generates a compiler error." << std::endl;
std::cout << "-------------------------------------------\n";
for ( int i = 32; i <= 100; i++ ) {
    std::cout << PWRTWO( i ) << std::endl;
}
person Francis Cugler    schedule 10.03.2016
comment
Обратите внимание, что последний образец (std::cout << PWRTWO(X >= 32) << std::endl;) будет печатать либо 1, либо 2 на каждой машине (при условии, что X определен где угодно), потому что X >= 32 оценивается как 0 (ложь) или 1 (истина). Отрицательный аргумент приведет к неопределенному поведению, как и аргумент, превышающий sizeof(int) * CHAR_BIT. - person Jonathan Leffler; 10.03.2016
comment
@JonathanLeffler Вы неверно истолковали мое намерение использовать выражение (x ›= 32). Он предназначен для обозначения фактических значений, вводимых в макрос, таких как 32, 33, 34, 35 и т. д., а не самого фактического выражения, и на моем компьютере с Windows 7 он отображает 0 в каждом случае ›= 32. Я извините за эту путаницу, я отредактирую и добавлю комментарий в исходный ответ, чтобы отразить это - person Francis Cugler; 11.03.2016
comment
Почему отрицательный голос? ОП запросил #define или макрос! И это сила двух макросов! - person Francis Cugler; 11.03.2016