How to Develop Static for Loop in C++

Is it possible to develop static for loop in c++?

Template metaprogramming in C++ is pure functional programming, and in pure functional programming you don't get to use loops like for or while and you don't get to have any mutable data at all. All you have is recursion. To make working with recursion easier, you need to rise abstraction level a bit. The recursive code that you have is fine, but the iteration and work can be split apart:

template <int First, int Last>
struct static_for
{
template <typename Fn>
void operator()(Fn const& fn) const
{
if (First < Last)
{
fn(First);
static_for<First+1, Last>()(fn);
}
}
};

template <int N>
struct static_for<N, N>
{
template <typename Fn>
void operator()(Fn const& fn) const
{ }
};

Now that you have this meta-function, you can write your deduce_mask function like this:

template<int Channel>
void deduce_mask(Matrix const &src, int mask[])
{
static_for<0, Channel>()([&](int i)
{
mask[mapper(0, 1, i)] = src(row - 1, col)[i];
mask[mapper(1, 1, i)] = src(row, col)[i];
mask[mapper(2, 1, i)] = src(row + 1, col)[i];
});
}

Visual C++ 2012 with /Ob1 command line switch compiles this code into this:

push        0  
call <lambda_7588286c1d4f3efe98a2e307bd757f8e>::operator() (010C1270h)
push 1
call <lambda_7588286c1d4f3efe98a2e307bd757f8e>::operator() (010C1270h)
push 2
call <lambda_7588286c1d4f3efe98a2e307bd757f8e>::operator() (010C1270h)
push 3
call <lambda_7588286c1d4f3efe98a2e307bd757f8e>::operator() (010C1270h)
push 4
call <lambda_7588286c1d4f3efe98a2e307bd757f8e>::operator() (010C1270h)
...

If you can't use lambda functions, you need to write a functor. Functor has one advantage over lambda function - you can specify a calling convention (if you don't mind doing that). If the operator() of the functor has __fastcall calling convention then you will see mov edx, x instead of push x in the assembler code.

Static Variable & For Loop

The problem is that Func() returns immediately after i is printed out, i++ (as the iteration_expression of for loop) is not evaluated at all.

You might want (even the loop seems meaningless here, the function always returns at the 1st iteration) :

void Func()
{
static int i = 0;

for (;i < 5;)
{
std::cout << i << "\n";
i++;
return;
}
}

Or

void Func()
{
static int i = 0;

for (;i < 5;)
{
std::cout << i++ << "\n";
return;
}
}

PS: I'm not sure about your intent, but as @FrançoisAndrieux and @Jarod42 commented, using if or while seems to make more sense, if you want i to be increased everytime Func() is called but won't be larger than 5.

Static variable in 'for' loop initial declaration

C does not allow it

C11dr 6.8.5 Iteration statements 3

"The declaration part of a for statement shall only declare identifiers for objects having storage class auto or register".

(not static)


Typically code would not benefit form being able to have an iterator that is static.


storage-class-specifier:

typedef
extern
static
_Thread_local
auto
register

Lambda in for loop - static variable

Think of a lambda expression as a terse recipe to define a class that overloads the call operator(). In your case:

struct LambdaEquivalent {
int j;

auto operator() const
{
static int s{j};
cout << s << endl;
}
};

And you loop then is

for(int i = 0; i < 5; ++i)
{
int j = i + 1;
LambdaEquivalent k{j};
k()
}

This illustrates that any local static data in the body of a lambda expression is nothing but local static data in a member function - and that is initialized exactly once. It's a good thing that both cases behave identically, handling it differently could be very confusing.

Initialize a new static variable every loop, C++

What is a static variable?

In most operating systems the global variables and all static variables are placed into the program image in their own data section. If they have complicated initialization then those are run on program start, or protected with locks and set on first use.

The only difference between global and static variables is that the compiler will not allow your program to use a static variable that is outside the current scope. From an assembly language viewpoint, statics and globals are identical.

Since all globals and statics are created from the program image at startup, you cannot add more of them later.

If you want to use dynamic amounts of memory that grows over time, you need to use the heap. C++ has new T, new T[], delete and delete[] in order to handle that. The C++ standard containers use allocators, which in turn call new in special ways. Normally you don't worry about allocators and just use the containers.

Some fun details!

I made a little C file which I compiled into a .o all on its own, so it wouldn't get optimized away when combined with main. All main does is call f().

#include <stdio.h>

int global_0;
int global_1 = 1;
int global_2 = 2;

static int static_0;
static int static_3 = 3;
static int static_4 = 4;

int f() {
static int static_func_0;
static int static_func_5 = 5;

printf("%p\n", (void *)&global_0);
printf("%p\n", (void *)&global_1);
printf("%p\n", (void *)&global_2);

printf("%p\n", (void *)&static_0);
printf("%p\n", (void *)&static_3);
printf("%p\n", (void *)&static_4);

printf("%p\n", (void *)&static_func_0);
printf("%p\n", (void *)&static_func_5);

return 0;
}

And then a few inspections of the resulting program:

$ objdump -t ./global-static-test
[...snipped a bunch of junk...]
000000001002002c l O .data 0000000000000004 global_1
0000000010020030 l O .data 0000000000000004 global_2
0000000010020034 l O .data 0000000000000004 static_3
0000000010020038 l O .data 0000000000000004 static_4
000000001002003c l O .data 0000000000000004 static_func_5.0
0000000010020044 l O .bss 0000000000000004 global_0
0000000010020048 l O .bss 0000000000000004 static_0
000000001002004c l O .bss 0000000000000004 static_func_0.1

So you can see that the globals, the file scope statics and the function statics are all huddled together in .data and .bss sections.

The reason for .bss is it is for all zero-initialized things. The program loader does not actually load .bss. Instead it just allocates some number of zero-filled memory pages. A global array of a hundred megabytes wouldn't need to be read off of disk, as long as it contained only zeroes.

And the reason the "_func_" variables have numbers on the end is because you could have many functions with static variables, all with the same names. The compiler adds a number to make each one unique.

And here's the contents of .data

$ objdump -s -j .data ./global-static-test
./global-static-test: file format elf64-powerpcle

Contents of section .data:
10020028 00000000 01000000 02000000 03000000 ................
10020038 04000000 05000000 ........

Why is my static_for implementation in C++ slower than regular 'for' loop

I would try this:

template <typename Lambda>
static inline constexpr void apply(Lambda&& f)

I've found passing by reference for this kind of meta programming can sometimes cause the compiler to do the wrong thing.

And for good measure you could also FORCE_INLINE:

#if defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#else
#define FORCE_INLINE __attribute__((always_inline))
#endif

Define variable before while loop or as static in loop

(1) Is it good practice/does it make sense to define the variable timeout_x100us as static inside the loop to minimize its scope?

Generally it is good practice to reduce scope of variables. Regardless of that, you need to set it to a value in run-time before it is used.

However, for embedded systems specifically, it is bad practice to write code that relies on static storage initialization (of .data/.bss). Partially because a very long time could have passed between initialization and variable use, partially because it is common to use non-standard start-up code in the CRT that doesn't even initialize such variables.

What you should do is to keep timeout_x100us as a local variable with automatic storage, then initialize it to a value before executing the code, each time.

Also replace the magic number 50000 with a meaningful named #define.

Also keep in mind that the integer constant 50000 is of type 32 bit long on PIC, which is potentially a performance-killing bug. Replace it with 50000u to ensure 16 bit unsigned int instead.

You should be able to replace the code with something like this:

uint16_t i;
for(i=0; !is_interruptflag() && i<TIMEOUT; i++)
{
__delay_us(100);
}

if(i==TIMEOUT)
{
return ;
}

(2) I am also trying to minimize program memory usage. The first code snippet uses 36 bytes of memory, whereas the second one (static) uses 54 bytes

The first uses the stack instead, so it simply uses a different kind of memory. The extra code bloat could be related to some PIC Harvard architecture hiccup. Disassemble and investigate why.



Related Topics



Leave a reply



Submit