functions that take many arguments...... + extern - what about it?

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

So I thought to myself, perhaps this is beginning to get out of hands if
I continue to put in extra functionality in the (file-writing)
output-functions....

I thought to myself that perhaps I should begin to assemble some of the
2D pointers into some structures and then pass the pointer to the
"container" structure, even though I probably wont be needing all
pointers in the structure. That should get rid of a a few of function
arguments... Or would it be completely acceptable to live with say 20
arguments? As an example... Take this function:



void vtk_output(int nx, int ny, int nz, double *xvalues,
double *yvalues, double *zvalues,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
int show_p_locations, int show_rhocp,
unsigned number_of_interior_cells,
int *output_filestep, int output_direction,
int num_integration, int show_boundary)


I'm passing some integers that either has the value 0 or 1... Perhaps I
should rewrite the program and use some bit-fiddling stuff - using
logical AND / OR for comparing?

The following holds either 0 or 1:

int show_p_locations,
int show_rhocp,
int num_integration,
int show_boundar

And int output_direction is {0, 1, 2 or 3}.

Is there a good way of passing say.... "int control_stuff" where

control_stuff (bit 0) = show_p_locations;
control_stuff (bit 1) = show_rhocp
control_stuff (bit 2) = int num_integration,
control_stuff (bit 3) = int show_boundar
control_stuff (bit 4....7) = reserved for future use...

?

And does any upper limit exists - something about stack overflow or
something to consider, if one passes say 100 arguments (not that I could
think of doing it)?

Also, I never use any "extern" prototypes in my header files. I didn't
get any problems yet so I don't see why the "extern" keyword exists in
the first place? From what I've read various places, this extern keyword
just tells that the definition? is placed in another source file (AFAIR
- something like that)?



Best regards
Martin Jørgensen
 
D

Dann Corbit

Martin Jørgensen said:
Hi,

Problem:
========
Some of my output functions are beginning to take pretty many arguments...
I mean.... We're talking about 10-15 arguments :)

So I thought to myself, perhaps this is beginning to get out of hands if I
continue to put in extra functionality in the (file-writing)
output-functions....

I thought to myself that perhaps I should begin to assemble some of the 2D
pointers into some structures and then pass the pointer to the "container"
structure, even though I probably wont be needing all pointers in the
structure. That should get rid of a a few of function arguments... Or
would it be completely acceptable to live with say 20 arguments? As an
example... Take this function:



void vtk_output(int nx, int ny, int nz, double *xvalues,
double *yvalues, double *zvalues,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
int show_p_locations, int show_rhocp,
unsigned number_of_interior_cells,
int *output_filestep, int output_direction,
int num_integration, int show_boundary)


I'm passing some integers that either has the value 0 or 1... Perhaps I
should rewrite the program and use some bit-fiddling stuff - using logical
AND / OR for comparing?

The following holds either 0 or 1:

int show_p_locations,
int show_rhocp,
int num_integration,
int show_boundar

And int output_direction is {0, 1, 2 or 3}.

Is there a good way of passing say.... "int control_stuff" where

control_stuff (bit 0) = show_p_locations;
control_stuff (bit 1) = show_rhocp
control_stuff (bit 2) = int num_integration,
control_stuff (bit 3) = int show_boundar
control_stuff (bit 4....7) = reserved for future use...

?

And does any upper limit exists - something about stack overflow or
something to consider, if one passes say 100 arguments (not that I could
think of doing it)?

Also, I never use any "extern" prototypes in my header files. I didn't get
any problems yet so I don't see why the "extern" keyword exists in the
first place? From what I've read various places, this extern keyword just
tells that the definition? is placed in another source file (AFAIR -
something like that)?

If the function is called recursively, then overflow of the stack (automatic
memory) might be a worry.
If your function is passing 100 arguments, then you have written a function
that is literally impossible to debug.
Almost for certain, this is a bad design.

If you are passing 20 arguments, then you have a function that is incredibly
difficult to debug.
Since 80% of the cost of software is maintenance, I think that is what
should really curtail how much stuff we pass into our functions. By making
the functions as small and simple as possible, we make them much easier to
debug and hence to maintain.

There are times when the complexity of the problem requires lots of
parameters to our function. In such cases, we will have to rely on
probabilistic testing + code coverage + endpoint (fencepost) style tests.

So I guess that I am saying that we should limit (as much as possible) the
arguments we pass into a function. But the reason is not due to stack
(we'll call it automatic memory here to avoid problems) but rather is due to
the difficulty of ensuring correctness with a monstrous pile of inputs.

IMO-YMMV.
 
R

Rafael Almeida

I thought to myself that perhaps I should begin to assemble some of
the 2D pointers into some structures and then pass the pointer to the
"container" structure, even though I probably wont be needing all
pointers in the structure. That should get rid of a a few of function
arguments... Or would it be completely acceptable to live with say 20
arguments? As an example... Take this function:



void vtk_output(int nx, int ny, int nz, double *xvalues,
double *yvalues, double *zvalues,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
int show_p_locations, int show_rhocp,
unsigned number_of_interior_cells,
int *output_filestep, int output_direction,
int num_integration, int show_boundary)
I think you might have too much being done in one function, you might
want to have more than one output function. Maybe one for each kind of
data. That will probably make thing neater.
And does any upper limit exists - something about stack overflow or
something to consider, if one passes say 100 arguments (not that I
could think of doing it)?
I think C specification specifies a minimum for number of arguments but
not a maximum, although most implementations probably have a limit.
You should check the documentation for the compiler you're using. Of
course, depending on the size of the structures being passed as
parameters you could have memory limitation issues. But you really
shouldn't think about passing that many parameters to a function.
 
P

Peter Nilsson

Martin said:
Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

The only C language issue you've raised is the minimum translation
limit...

* 31 parameters in one function definition
* 31 arguments in one function call

[In C99 it's 127 parameters and arguments.]
So I thought to myself, perhaps this is beginning to get out of hands if
I continue to put in extra functionality in the (file-writing)
output-functions....

I thought to myself that perhaps I should begin to assemble some of the
2D pointers into some structures and then pass the pointer to the
"container" structure,

Or do what most low level file I/O does, use pointers to parameter
blocks.
even though I probably wont be needing all
pointers in the structure. That should get rid of a a few of function
arguments... Or would it be completely acceptable to live with say 20
arguments?

It depends. You're more likely to hit implementation/platform and
general programming
issues than actual language issues.
As an example... Take this function:

void vtk_output(int nx, int ny, int nz, double *xvalues,
double *yvalues, double *zvalues,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
int show_p_locations, int show_rhocp,
unsigned number_of_interior_cells,
int *output_filestep, int output_direction,
int num_integration, int show_boundary)


I'm passing some integers that either has the value 0 or 1... Perhaps I
should rewrite the program and use some bit-fiddling stuff - using
logical AND / OR for comparing?

The following holds either 0 or 1:

int show_p_locations,
int show_rhocp,
int num_integration,
int show_boundar

And int output_direction is {0, 1, 2 or 3}.

Is there a good way of passing say.... "int control_stuff" where

control_stuff (bit 0) = show_p_locations;
control_stuff (bit 1) = show_rhocp
control_stuff (bit 2) = int num_integration,
control_stuff (bit 3) = int show_boundar
control_stuff (bit 4....7) = reserved for future use...

?

Consider the way that open works in POSIX, but it ain't pretty IMNSHO.
And does any upper limit exists - something about stack overflow or
something to consider, if one passes say 100 arguments (not that I could
think of doing it)?

See above.
Also, I never use any "extern" prototypes in my header files.

The lack of extern is incidental, the lack of prototype for such
functions is
criminal. ;-)
I didn't get any problems yet so I don't see why the "extern" keyword exists
in the first place? From what I've read various places, this extern keyword
just tells that the definition? is placed in another source file (AFAIR
- something like that)?

It says that the identifier being delcared has external linkage. It
needn't
be in another source file per se. [With headers, it's not always clear
what
'another source file' means since the header itself is usually another
source
file!]

It's basically redundant, but not quite as redundant as 'auto'.
 
A

Al Balmer

Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

So I thought to myself, perhaps this is beginning to get out of hands if
I continue to put in extra functionality in the (file-writing)
output-functions....

I thought to myself that perhaps I should begin to assemble some of the
2D pointers into some structures and then pass the pointer to the
"container" structure, even though I probably wont be needing all
pointers in the structure.

All this would indicate to me that it's time to re-think the design.
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Dann said:
-snip-

If you are passing 20 arguments, then you have a function that is incredibly
difficult to debug.
Since 80% of the cost of software is maintenance, I think that is what
should really curtail how much stuff we pass into our functions. By making
the functions as small and simple as possible, we make them much easier to
debug and hence to maintain.

Inside the function, it then calls other functions so the problem is
split up into smaller pieces...
There are times when the complexity of the problem requires lots of
parameters to our function. In such cases, we will have to rely on
probabilistic testing + code coverage + endpoint (fencepost) style tests.

How is that done?
So I guess that I am saying that we should limit (as much as possible) the
arguments we pass into a function. But the reason is not due to stack
(we'll call it automatic memory here to avoid problems) but rather is due to
the difficulty of ensuring correctness with a monstrous pile of inputs.

Ok.



Best regards
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Rafael said:
I think you might have too much being done in one function, you might
want to have more than one output function. Maybe one for each kind of
data. That will probably make thing neater.

But it should all be written to the same file.... Hmm... But ok, good
point. Could probably be done. I just pass in FILE *fp as argument to
each sub-function.
I think C specification specifies a minimum for number of arguments but
not a maximum, although most implementations probably have a limit.
You should check the documentation for the compiler you're using. Of
course, depending on the size of the structures being passed as
parameters you could have memory limitation issues. But you really
shouldn't think about passing that many parameters to a function.

Do you mean it's a compiler issue if the number of arguments are too many?


Best regards
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Peter said:
Martin said:
Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)


The only C language issue you've raised is the minimum translation
limit...

* 31 parameters in one function definition
* 31 arguments in one function call

[In C99 it's 127 parameters and arguments.]

Don't you mean "the maximum limit"?
Or do what most low level file I/O does, use pointers to parameter
blocks.

Exactly what I was considering. Then I would have to rewrite a lot, but
that's okay...
It depends. You're more likely to hit implementation/platform and
general programming
issues than actual language issues.

How do I know if (as an example) 20 arguments would be too much.

Compiler error? Program crash? Unexpected behaviour? Something else?
Consider the way that open works in POSIX, but it ain't pretty IMNSHO.

I have no idea about where to find out about that and I don't really
know what POSIX is (ok, I just googled and found out that it's an
abbreviation: Portable Operating System Interface.... + A family of
open system standards based on Unix. Bash is concerned with POSIX
1003.2....)
See above.




The lack of extern is incidental, the lack of prototype for such
functions is
criminal. ;-)

I have prototypes in my header files. They're just not "extern"...
I didn't get any problems yet so I don't see why the "extern" keyword exists
in the first place? From what I've read various places, this extern keyword
just tells that the definition? is placed in another source file (AFAIR
- something like that)?


It says that the identifier being delcared has external linkage. It
needn't
be in another source file per se. [With headers, it's not always clear
what
'another source file' means since the header itself is usually another
source
file!]

It's basically redundant, but not quite as redundant as 'auto'.

Why do you have the "extern" keyword in front of the prototypes when it
seems unnecessary?


Best regards
Martin Jørgensen
 
C

Chris Dollin

Martin said:
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

I'd say that was about 10 too many, just on general principles.
 
J

John Bode

Martin said:
Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

So I thought to myself, perhaps this is beginning to get out of hands if
I continue to put in extra functionality in the (file-writing)
output-functions....

I thought to myself that perhaps I should begin to assemble some of the
2D pointers into some structures and then pass the pointer to the
"container" structure, even though I probably wont be needing all
pointers in the structure. That should get rid of a a few of function
arguments... Or would it be completely acceptable to live with say 20
arguments?

As with everything else in software, the answer is "it depends."

Don't arbitrarily group items together that don't otherwise form a
logical aggregate. Anything that *does* form a logical aggregate
should be grouped together, but that should be true for the entire
design, not just for an individual function call. For example, I have
no idea what xvalues, yvalues, and zvalues represent in your code, but
if they're coordinates in 3-space, then they could be grouped together
as a "position" aggregate (although instead of a struct of arrays,
you'd use an array of structs, with each struct containing a single {x,
y, z} value).

Similarly, you could group all your flags in another aggregate type
("output_flags") or some such, since they're all logically related
(together they determine the format of your output). You could use a
bitmask for this, but personally I think using a struct is more
straightforward.

If you find that you have twenty arguments that aren't logically
connected except for the fact that this particular function uses them,
then you really do need to rethink your design. However, it does
occasionally happen that you just wind up with functions with large
parameter lists; in those cases, the best thing to do is just document
the hell out of everything.

[snip remainder]
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

John said:
Martin Jørgensen wrote: -snip-

no idea what xvalues, yvalues, and zvalues represent in your code, but
if they're coordinates in 3-space, then they could be grouped together
as a "position" aggregate (although instead of a struct of arrays,
you'd use an array of structs, with each struct containing a single {x,
y, z} value).

Ok, thanks. Gave me something to think about.
Similarly, you could group all your flags in another aggregate type
("output_flags") or some such, since they're all logically related
(together they determine the format of your output). You could use a
bitmask for this, but personally I think using a struct is more
straightforward.
Agreed.

If you find that you have twenty arguments that aren't logically
connected except for the fact that this particular function uses them,
then you really do need to rethink your design. However, it does
occasionally happen that you just wind up with functions with large
parameter lists; in those cases, the best thing to do is just document
the hell out of everything.

I think I've come to a conclusion... If it grows much more, I could
probably rewrite the code and move it into main() where it could see
anything (all variables) instead of getting all kinds of parameters from
main(). It's just that in the beginning this function didn't took many
parameters... And then it growed... And growed... And growed :)


Best regards
Martin Jørgensen
 
K

Keith Thompson

Martin Jørgensen said:
Peter said:
Martin said:
Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)
The only C language issue you've raised is the minimum translation
limit...
* 31 parameters in one function definition
* 31 arguments in one function call
[In C99 it's 127 parameters and arguments.]

Don't you mean "the maximum limit"?

It's actually the minimum maximum limit. Each implementation is
allowed to impose a maximum limit on the number of parameters in a
function definition. In C90, that maximum limit must be *at least*
31; in C99, it must be at least 127. Implementations may, and
commonly do, impose a higher limit, or no fixed limit at all.

[...]
How do I know if (as an example) 20 arguments would be too much.

Compiler error? Program crash? Unexpected behaviour? Something else?

Confusion. Your compiler will never give you any problems with up to
31 arguments, but you'll find it impossible to keep track of things
yourself long before that.

[...]
 
M

Michael Mair

Martin said:
Peter said:
Martin said:
Hi,

Problem:
========
Some of my output functions are beginning to take pretty many
arguments... I mean.... We're talking about 10-15 arguments :)

The only C language issue you've raised is the minimum translation
limit...

* 31 parameters in one function definition
* 31 arguments in one function call

[In C99 it's 127 parameters and arguments.]

Don't you mean "the maximum limit"?

No. This is the minimal value that your implementation may take as
maximum, i.e. it is allowed to "throw up" at 32 parameters/arguments
but it may as well accept up to 12345 or whatever strikes its fancy.

How do I know if (as an example) 20 arguments would be too much.

Compiler error? Program crash? Unexpected behaviour? Something else?

Your implementation _must_ document its actual limits if it is
a conforming implementation of some sort.
The above minimum translation limits let you know that you may
have up to 31 arguments without having to worry -- above that,
you have to look at your implementation's documentation.

<snip>

The above can easily be rewritten to
void vtk_output(struct valueTupel *values,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
unsigned number_of_interior_cells,
int *output_filestep, struct vtk_out_flags *flags)

where
struct valueTupel {
int num;
double *value;
};
and where the "directions" of values can be accessed by, say
enum { X_, Y_, Z_ };
and where
struct vtk_out_flags {
unsigned int show_p_locations: 1;
unsigned int show_p_rhocp: 1;
unsigned int num_integration: 1;
unsigned int show_boundar: 1;
unsigned int output_direction: 2;
};
However, this is just grouping what you have told us about/
what is obvious.
Try to group parameters using struct by the following criteria:
- belong logically together (like nx+xvalues); example:
it is unclear with which number(s) the double ** parameters are
corresponding but if it is always the same, you can group the
numbers and the double ** parameters
- are passed together to functions called from vtk_output().
Say you pass on output_filestep and number_.... and p_locations,
then group them.
If this does not bring you below 5 to 7 parameters, consider a
redesign of your programme in earnest.

The lack of extern is incidental, the lack of prototype for such
functions is
criminal. ;-)

I have prototypes in my header files. They're just not "extern"...
I didn't get any problems yet so I don't see why the "extern" keyword
exists
in the first place? From what I've read various places, this extern
keyword
just tells that the definition? is placed in another source file (AFAIR
- something like that)?

It says that the identifier being delcared has external linkage. It
needn't
be in another source file per se. [With headers, it's not always clear
what
'another source file' means since the header itself is usually another
source
file!]

It's basically redundant, but not quite as redundant as 'auto'.

Why do you have the "extern" keyword in front of the prototypes when it
seems unnecessary?

Historic reasons / parallel use to variable declarations.

For one thing, you can use the keyword to make clear that you thought
about making the functions "static" (internal linkage) but decided to
make them "extern"... :)


Cheers
Michael
 
M

Malcolm

Martin Jørgensen said:
Inside the function, it then calls other functions so the problem is split
up into smaller pieces...
So if there is a natural hierarchy, express that in structures.
For example you have nx, ny, nz values, and then lists of doubles. It seems
to me that this very easily falls into a group

typedef struct
{
double *x;
double *y;
double *z;
int nx;
int ny;
int nz;
} COORDINATESET;

I am slightly puzzled that nx, ny and nz are different. So put a comment in
the structure definition explaining why this needs to be so.

Similarly the show_ members are probably booleans. It is not usual to pass
these as flags

#define SHOW_PLOCATONS 1
#define SHOW_RHOCP 2
#define SHOW_BOUNDARY 4
#define SHOW_NOTHING 0
That makes the call more humanly-readable, and you only need one parameter.

How is that done?
Code coverage means that you write your tests so that every line of code is
executed at least once. So if you have an exit(0) after a malloc() call, you
artificially manipluate the malloc() to fail at least once at that point.
You can get automatic tools that will help you do this.

Most errors come when data is at the extremes of the range the code is
expected to handle. So for instance if a function takes a string, it is a
good test to pass it an empty string. If it is specified that the string can
be 256 bytes long, pass it one exactly 256 bytes long and see whether
allowance has been made for the null. This applies particularly to loops.
Are the first and the last items in the list processed correctly?

Probabilistic testing means that we haven't shown the program to be
absolutely correct, but we have given enough test cases to make it a
reasonable bet that the program is in fact accurate. It is very difficult to
detect if a function chokes on the input telephoneno = "666". However why
should it? If "666" is hardcoded into the function we should pick it up on a
coverage test. But there just might be some gremlin in there, if it happens
to hash to zero and we have forgotten that zero is a valid slot in the
table, for instance. Even this should have been picked up by an endpoint
test, but you can't expect to get everything right with limited time and
budget.
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Malcolm said:
So if there is a natural hierarchy, express that in structures.
For example you have nx, ny, nz values, and then lists of doubles. It seems
to me that this very easily falls into a group

typedef struct
{
double *x;
double *y;
double *z;
int nx;
int ny;
int nz;
} COORDINATESET;

Yes, good idea... That would get rid of a lot...
I am slightly puzzled that nx, ny and nz are different. So put a comment in
the structure definition explaining why this needs to be so.

Ok, it's basically just nx = number of cells in the x-direction. double
*x then holds the distances between each element... So inside the
function: for(i=0; i<nx< i++) etc...
Similarly the show_ members are probably booleans. It is not usual to pass
these as flags

#define SHOW_PLOCATONS 1
#define SHOW_RHOCP 2
#define SHOW_BOUNDARY 4
#define SHOW_NOTHING 0
That makes the call more humanly-readable, and you only need one parameter.

I can't do that, because those values are read from an input file
(input.txt).
Code coverage means that you write your tests so that every line of code is
executed at least once. So if you have an exit(0) after a malloc() call, you
artificially manipluate the malloc() to fail at least once at that point.
You can get automatic tools that will help you do this.

So the program terminates before it's supposed to do?
Most errors come when data is at the extremes of the range the code is
expected to handle. So for instance if a function takes a string, it is a
good test to pass it an empty string. If it is specified that the string can
be 256 bytes long, pass it one exactly 256 bytes long and see whether
allowance has been made for the null. This applies particularly to loops.
Are the first and the last items in the list processed correctly?
Ok.

Probabilistic testing means that we haven't shown the program to be
absolutely correct, but we have given enough test cases to make it a
reasonable bet that the program is in fact accurate. It is very difficult to
detect if a function chokes on the input telephoneno = "666". However why
should it? If "666" is hardcoded into the function we should pick it up on a
coverage test. But there just might be some gremlin in there, if it happens
to hash to zero and we have forgotten that zero is a valid slot in the
table, for instance. Even this should have been picked up by an endpoint
test, but you can't expect to get everything right with limited time and
budget.

Agreed... Sounds like my program... I have made a lot of tests, but I
don't really know if there is some "666"-situation, where it gives a
wrong result...


Best regards
Martin Jørgensen
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael said:
Martin Jørgensen schrieb: -snip-


<snip>

The above can easily be rewritten to
void vtk_output(struct valueTupel *values,
double **temp_array, double **porosities,
double **local_rhocp, double **p_locations,
unsigned number_of_interior_cells,
int *output_filestep, struct vtk_out_flags *flags)

where
struct valueTupel {
int num;
double *value;
};
and where the "directions" of values can be accessed by, say
enum { X_, Y_, Z_ };
and where
struct vtk_out_flags {
unsigned int show_p_locations: 1;
unsigned int show_p_rhocp: 1;
unsigned int num_integration: 1;
unsigned int show_boundar: 1;
unsigned int output_direction: 2;
};
However, this is just grouping what you have told us about/
what is obvious.

Thanks... I'm not so good at using structs, so now I can practice using
them... However I agree it's probably "easy" to change this function
itself... The problem is that I must do a search/replace in my whole
program to modify all these variables in the whole program.... And that
could probably at least take me a couple of days... :)

But using structs is a better way... I'll try it at some moment...
Try to group parameters using struct by the following criteria:
- belong logically together (like nx+xvalues); example:
it is unclear with which number(s) the double ** parameters are
corresponding but if it is always the same, you can group the
numbers and the double ** parameters

Agreed. Good solution.
- are passed together to functions called from vtk_output().
Say you pass on output_filestep and number_.... and p_locations,
then group them.
If this does not bring you below 5 to 7 parameters, consider a
redesign of your programme in earnest.

It's a good start...

-snip (extern keyword)
Historic reasons / parallel use to variable declarations.

For one thing, you can use the keyword to make clear that you thought
about making the functions "static" (internal linkage) but decided to
make them "extern"... :)

Ok, thanks.


Best regards
Martin Jørgensen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,973
Members
47,529
Latest member
JaclynShum

Latest Threads

Top