-1

For a homework assignment, we've been asked to write a preprocessor macro that sums the elements of an array.

My question is, how can I process array elements within a macro in such a way that could expand to a sum (or any other mathematical operation on the elements)?

There's nothing in our book that mentions processing array elements or even accessing them, and I can't find many helpful resources online as a macro wouldn't be the typical way to deal with something like this. I know there are way better ways to do such a thing, but I understand that the idea is to get us better familiar with preprocessor macros.

When I go about writing the macro in the style of a function, I don't know how to "return" the sum to the program. The only way I can think of to get the macro to expand to a sum is if it were done recursively, and I'm not even sure if you can recurse with macros. I've written a macro that successfully expands to the size of the array, but I'm not sure which direction to go from there.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 3
    C++ or C? They are very different languages with very different programming idioms and techniques. – L. F. Jul 15 '19 at 00:40
  • Remember you can write a function and call the function in the macro. – L. F. Jul 15 '19 at 00:41
  • Technically it's a C course, but we've been working with C++ throughout, so C++ would be the answer (it's a cpp file) – Dave Williams Jul 15 '19 at 00:42
  • The idea of the assignment is that it all has to be done with macros, so I'm not allowed to call a function. – Dave Williams Jul 15 '19 at 00:43
  • 5
    Is this a high school or a college level "C course"? I can state with 100% certainty that absolutely nothing useful in terms of practical C, or C++, programming skills would be learned from crafting such a macro. – Sam Varshavchik Jul 15 '19 at 00:51
  • Are you allowed to use a loop in the macro? – eesiraed Jul 15 '19 at 00:55
  • 1
    Doing all this with constexpressions would be better than macros. – wally Jul 15 '19 at 00:56
  • I understand that wally, but we're not allowed to use functions or constexpressions. The concept behind the assignment is that it must be done entirely with macros. – Dave Williams Jul 15 '19 at 02:27
  • Alexander zhang, yes, I can use loops or any other control structure so long as the problem is solved entirely with macros. – Dave Williams Jul 15 '19 at 02:28
  • Sam, it's college level. I agree, it's a useless exercise. – Dave Williams Jul 15 '19 at 02:29
  • @L.F. Isn't the preprocessor is basically the same between C and C++? – Jerry Jeremiah Jul 15 '19 at 02:55
  • 1
    Does this help? https://stackoverflow.com/questions/319328/how-to-write-a-while-loop-with-the-c-preprocessor – Jerry Jeremiah Jul 15 '19 at 02:56
  • @JerryJeremiah The preprocessor itself may not differ that much, but consider what the macros are supposed to expand to ... – L. F. Jul 15 '19 at 02:56
  • As far as "returning" the sum, is there a way to write to a variable referenced in one of the arguments of the macro? And is it possible to iterate through an array within a macro? If I were to iterate through the array, I would need some way to get that result inline within the code that implements it, because I don't see how a loop of unknown iterations (i.e., traversing and processing elements in an array) could expand to a single result. This is such a stupid, stupid assignment... – Dave Williams Jul 15 '19 at 03:52
  • Maybe something like `#define sum(x, a) do { x = 0; for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) x += a[i]; } while(false)`? – eesiraed Jul 15 '19 at 04:03

2 Answers2

1

Here is an answer using c++14:

#include <array>
#include <iostream>
#include <numeric>
#include <type_traits>
#include <vector>

#define SUM(ARY) \
  std::accumulate( \
      std::begin(ARY), \
      std::end(ARY), \
      std::remove_reference_t<decltype(ARY[0])>{})
int
main()
{
  auto ary1 = std::array< int, 5 >{1,2,3,4,5};
  std::cout << SUM(ary1) << "\n";

  int ary2[] = {1,2,3,4,5};
  std::cout << SUM(ary2) << "\n";

  auto ary3 = std::vector< int >{1, 2, 3, 4, 5};
  std::cout << SUM(ary3) << "\n";

  double ary4[] = {1.1,2.2,3.3,4.4,5.5};
  std::cout << SUM(ary4) << "\n";
}

Note that you don't "return" from a macro. A macro is text substitution. In the above where SUM(ary) appears, it is replaced with the expanded text of the SUM(ARY) macro definition.

You can extend this to other operations:

#include <array>
#include <iostream>
#include <numeric>

#define OP_ON_ARY(ARY, OP) \
  std::accumulate( \
      std::next(std::begin(ARY)), \
      std::end(ARY), \
      *std::begin(ARY), \
      [](auto a, auto b) { return a OP b; } \
      )

int
main()
{
  auto ary = std::array< int, 5 >{1,2,3,4,5};
  std::cout << OP_ON_ARY(ary, +) << "\n";
  std::cout << OP_ON_ARY(ary, -) << "\n";
  std::cout << OP_ON_ARY(ary, *) << "\n";
}

But using a function rather than a macro is more in the spirit of modern c++.

#include <array>
#include <iostream>
#include <numeric>
#include <vector>

template< typename Ary >
auto sum(Ary const & ary)
{
  return std::accumulate(
      std::begin(ary),
      std::end(ary),
      decltype(ary[0]){});
}

int
main()
{
  auto ary1 = std::array< int, 5 >{1,2,3,4,5};
  std::cout << sum(ary1) << "\n";

  int ary2[] = {1,2,3,4,5};
  std::cout << sum(ary2) << "\n";

  auto ary3 = std::vector< int >{1, 2, 3, 4, 5};
  std::cout << sum(ary3) << "\n";

  double ary4[] = {1.1,2.2,3.3,4.4,5.5};
  std::cout << sum(ary4) << "\n";
}
cff
  • 61
  • 2
  • Rather than assuming the container is non-empty, you can use the identity value for the operator. see http://coliru.stacked-crooked.com/a/d0e87e6123fe1cac – Caleth Jul 15 '19 at 16:14
  • This isn't exactly what he wanted in the assignment, but I was able to use what I learned from your solution to make mine work. Thanks! – Dave Williams Jul 15 '19 at 18:32
1

The preprocessor essentially does a lot of find and replace operations. It doesn't have any really advanced functionalities and certainly doesn't have any idea about what an array is. What I'd imagine that this assignment is asking you to do is to write some inline code to sum the array or something and then create a macro for it.

#define fold(array, ln, acc, op) \
  for(size_t i = 0; i < ln; ++i) \
    acc = acc op array[i];

int main(){
  int ar[10];
  int sum = 0;
  fold(ar, 10, sum, *); 
}

This code folds the array with the * operation.

Chris
  • 566
  • 2
  • 7
  • 22
  • 1
    I didn't know that you could use operators as arguments in a macro. This is interesting, that might be a useful thing to know. – Dave Williams Jul 15 '19 at 18:34