1

In C#, inside a class, we can have variables that are set during the constructor of the type, like such:

class ComplexNumber
{
 public double real {get; set;}
 public double imag {get; set;}
 public double abs {get;}
 public Complex Number(double real, double imag)
 {
  this.real = real;
  this.imag = imag;
  this.abs = Math.Pow(real*real + imag*imag , 0.5f);
 }
}

(I apologize if the C# code is wrong, I haven't written C# in a while and I'm using it purely for an analogy ) During the constructer, the value of 'abs' is set, so I wanted to know if in a C struct, it'd be possible to do the same, even though there is no constructor

typedef struct Comp
{
 double real;
 double imag;
 double abs;
} Comp;

int main(void)
{
 Comp z;
 z.real = 2.0f;
 z.imag = 5.3f;
 printf("%f\n" , z.abs);
}

So I'd like to be able to run the code up there and have it return a value for z.abs without ever actually setting it to anything (although it being set to something after both z.real and z.imag are set). Would this be feasible somehow in C?

edit: I have looked as Default values in a C Struct as suggested and in that question, they seem to want a default value for their own type, so a type that is preset, but on my case, what I would like to be able to do is, instead of setting the custom type to a default, every time I set a custom type, one of the attributes inside of it, 'z.abs' would be set using 'z.real' and 'z.imag' instead of having a default value, for examples:

Comp z;
z.real = 4.0f;
z.imag = 3.0f;

After writting this code, z is defined as { 4.0f, 3.0f, null/undefined}, but the last part of it, 'abs' can be calculated using the first two as sqrt(z.real^2 + z.imag^2) and so it's value is 5.0f. So I would want to, after setting the first two numbers, for the third one to be calculated automatically like a constructor in C#, the first example.

Filipe Rodrigues
  • 1,843
  • 2
  • 12
  • 21
  • Use [cabs](http://en.cppreference.com/w/c/numeric/complex/cabs) with ``. – BLUEPIXY Jul 14 '17 at 22:21
  • Possible duplicate of [Default values in a C Struct](https://stackoverflow.com/questions/749180/default-values-in-a-c-struct) – Ed Jaras Jul 14 '17 at 22:21
  • 1
    @EdJaras That question is about hard-coded defaults. Here he wants the default value of one member to be a function of the actual values of other members. – Barmar Jul 14 '17 at 22:33
  • I don't think the C# example does what you want. It initializes `abs` when the structure is created, but you seem to want it to get updated automatically whenever `real` or `imag` is assigned. – Barmar Jul 14 '17 at 22:34
  • Why don't you just make `abs` a member function rather than a variable? If you want to avoid recalculating it every time, it can be cached in a member variable. – Barmar Jul 14 '17 at 22:35
  • @BLUEPIXY I forgot to specify in the original question, but since I need to use the 'z.abs' various times in my code, it would take less processing power to just set it once and use it various time throughout my code, this because I am iterating through a lot of values for z and I need each iteration to be as quick as possible, otherwise I could use your solution to calculate it each time throughout my code. – Filipe Rodrigues Jul 14 '17 at 22:40
  • @Barmar Well yes, If I updated z.real or z.imag, z.abs would be incorrect, but I was thinking that I would run through the contructor each time I set them, so I then it'd be updated each time I ran through it, although I should have specified that I would have been setting it again each time I changed one of the variables. – Filipe Rodrigues Jul 14 '17 at 22:44
  • @Barmar In relation to why don't I make abs a member function, I have searched on google and it seems only c++ has member functions, not C, although I may have not looked well enough. – Filipe Rodrigues Jul 14 '17 at 22:46
  • You're right, I mistakenly thought you were asking about C++. – Barmar Jul 14 '17 at 22:47
  • @FilipeRodrigues in my edited answer, I addressed exactly that problem. For your C# code, if your intended use is to create a new object when a value changes, make **all** fields/properties `readonly`, not just `abs` :) –  Jul 14 '17 at 23:16
  • @FelixPalmen Yes, I've read your edit and it seems like a really interesting way to go about it, although since in this specific case I'm interested in performance a bit (although I forgot to specify that so the question was just in a general sense), when I need a more stable way to go about it, this 'class' method seems to be the best, Thank you. – Filipe Rodrigues Jul 14 '17 at 23:24
  • @FilipeRodrigues YW! It's a lot of boilerplate and also overhead for the additional function calls (but you have them in your C# example as well, just "hidden" by the syntax of automatic properties) AND the memory allocation. So I'd say it's never feasible to create a C "class" for a simple thing like this complex number class. I just wanted to draw the analogy, show the concept ;) –  Jul 14 '17 at 23:26
  • @FilipeRodrigues might be the C# compiler is smart enough to optimize away a lot of overhead for *automatic properties*, though ... I'm not sure about this. –  Jul 14 '17 at 23:27

3 Answers3

2

Given your C# code, what you have is a readonly automatic property. You could write your C# code instead like this:

class ComplexNumber
{
 public double real;
 public double imag;
 public readonly double abs;
 public ComplexNumber(double real, double imag)
 {
  this.real = real;
  this.imag = imag;
  this.abs = Math.Pow(real*real + imag*imag , 0.5f);
 }
}

For a moment, forget that this isn't the best style in C#. The relevant change is, your class now has just fields instead of properties and you can do something quite similar in C:

#include <stdio.h>
#include <math.h>

struct ComplexNumber
{
    double real;
    double imag;
    const double abs;
};

#define ComplexNumber_init(r,i) { \
    .real=(r), .imag=(i), .abs=pow((r)*(r)+(i)*(i), .5) }

int main(void)
{
    struct ComplexNumber cnum = ComplexNumber_init(4.0, 2.0);
    printf("%f\n", cnum.abs);
}

The key component here is the const qualifier on one struct member. With this, you can only set the value at initialization time, never later. The effect is quite comparable to C#'s readonly. C# has const, too, but with readonly, you can additinally set the value in the constructor.


If you want an equivalent to your original C# code, you must be aware that properties in C# always translate to methods -- getters and setters. In your example, you're using automatic properties, that means, as you don't specify a function body for your getters and setters, a default body is automatically created for you, simply accessing a private field.

There's no such thing in C, but you can create the same thing manually, an example follows.

Note I changed the semantics a bit, because having real and imag changeable without ever updating abs, as this is the case in your C# code, probably isn't the most sensible thing to do.

Also note this is complete overkill for this little example case, I'm just adding it to show a possibility how to write a "class" in C.

compnum.h:

#ifndef COMPNUM_H
#define COMPNUM_H

typedef struct ComplexNumber ComplexNumber;

// "constructor":

ComplexNumber *ComplexNumber_create(double real, double imag);

// getters and setters:

double ComplexNumber_real(const ComplexNumber *self);
void ComplexNumber_setReal(ComplexNumber *self, double real);

double ComplexNumber_imag(const ComplexNumber *self);
void ComplexNumber_setImag(ComplexNumber *self, double imag);

double ComplexNumber_abs(const ComplexNumber *self);

// "destructor":

void ComplexNumber_destroy(ComplexNumber *self);

#endif

compnum.c:

#include <math.h>
#include <stdlib.h>

#include "compnum.h"

// the struct itself is completed here and not in compnum.h -- this way, its
// members are *really* "private". They can't be seen by other translation
// units just including compnum.h.
struct ComplexNumber
{
    double real;
    double imag;
    // don't need abs here, it's calculated
};

ComplexNumber *ComplexNumber_create(double real, double imag)
{
    ComplexNumber *self = malloc(sizeof(*self));
    if (!self) return 0;
    self->real = real;
    self->imag = imag;
    return self;
}

double ComplexNumber_real(const ComplexNumber *self)
{
    return self->real;
}

void CompexNumber_setReal(ComplexNumber *self, double real)
{
    self->real = real;
}

double ComplexNumber_imag(const ComplexNumber *self)
{
    return self->imag;
}

void ComplexNumber_setImag(ComplexNumber *self, double imag)
{
    self->imag = imag;
}

double ComplexNumber_abs(const ComplexNumber *self)
{
    return pow(self->real*self->real + self->imag*self->imag, .5);
}

void ComplexNumber_destroy(ComplexNumber *self)
{
    free(self);
}

main.c:

#include <stdio.h>

#include "compnum.h"

int main(void)
{
    ComplexNumber *cnum = ComplexNumber_create(4.0, 2.0);
    printf("%f\n", ComplexNumber_abs(cnum));
    ComplexNumber_destroy(cnum);
}
unalignedmemoryaccess
  • 7,246
  • 2
  • 25
  • 40
  • Apart from not being able to set abs due to it being a constant, are there any other differences involved in abs being a const? Such as higher / lower memory allocation / processing time or any other factors over leaving it as a variable but still using the #define ComplexNumber_init to define abs at creation? Also, any differences between using the macro #define or making ComplexNumber_init a function like David has answered? – Filipe Rodrigues Jul 14 '17 at 22:57
  • @FilipeRodrigues The `const` ensures it can **only** be set at initialization, so it's impossible to set it using a function. This is the closest possible to your original C# code. I'm still working on an edit showing you an approach using OOP instead to solve this. –  Jul 14 '17 at 22:59
  • I considered a macro here, but it seems like there is less opportunity to catch, e.g., overflow errors this way. `const`ness may make up for it in some uses.... – ad absurdum Jul 14 '17 at 23:01
  • @FilipeRodrigues forget this, if your function returns the *struct* itself, of course this is possible with a function as well. It has a slight overhead though, it needs to copy the struct from the function to the caller. –  Jul 14 '17 at 23:01
  • So by using #define to make the function I trade away the possibily of catching errors such as overflow for a possible slight increase in performance. I suppose I could use both approches in different scenarios, so I'll keep both in mind. – Filipe Rodrigues Jul 14 '17 at 23:07
  • Also quick question about this page, since there can only be one 'accepted answer' what should I put since both questions give a correct answer but via different solutions? – Filipe Rodrigues Jul 14 '17 at 23:09
  • @FilipeRodrigues you're not obliged to choose any, but if you choose any, it should be the one that helped you **most**. IOW, it's up to you. It's not uncommon that there is more than one "correct" answer –  Jul 14 '17 at 23:13
1

If you don't explicitly set a field in a struct, it's contents are unspecified.

You can initialize the values of the struct as follows:

Comp z = { 0.0, 0.0, 0.0 };
dbush
  • 205,898
  • 23
  • 218
  • 273
  • I understand that they are unspecified, but since the third value 'abs' depends purely on the first 2 and should not be eddited, I was wondering if by setting only the first 2 values, 'real' and 'imag' it would be possible to tell the struct that 'abs' should be equal to sqrt(real^2 + imag^2) without having to formally write z.abs = pow(pow(z.real,2)+pow(z.imag,2),0.5f); since it would get very messy when a lot of variables are involved – Filipe Rodrigues Jul 14 '17 at 22:23
  • @FilipeRodrigues No, nothing like that. You'd need to make a function that given the real and imaginary parts will set both as well as `abs. – dbush Jul 14 '17 at 22:25
  • 2
    You can simply set all fields to zero like this: `Comp z = {0};` – Erik W Jul 14 '17 at 22:27
1

If you want to "initialize" a new struct to some predetermined values, some of which must be calculated from the values of other members, you can use a function that returns a struct:

#include <stdio.h>
#include <math.h>

typedef struct Comp
{
 double real;
 double imag;
 double abs;
} Comp;

Comp new_Comp(double re, double im);

int main(void)
{
    Comp my_comp = new_Comp(3.0, 4.0);

    printf("my_comp.real = %f, my_comp.imag = %f, my_comp.abs = %f\n",
           my_comp.real, my_comp.imag, my_comp.abs);

    return 0;
}

Comp new_Comp(double re, double im)
{
    Comp new = { .real = re, .imag = im };
    new.abs = hypot(re, im);

    return new;
}
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
  • This seems to work beautifully, it reduces the clutter of having to set 'z.abs' each time I make a new variable or the processing power of having to calculate 'abs(z)' each time I need it, Thank you. – Filipe Rodrigues Jul 14 '17 at 22:41
  • 1
    @FilipeRodrigues-- One nice thing about the [`hypot()`](http://port70.net/~nsz/c/c11/n1570.html#7.12.7.3) function, which returns __sqrt(x**2 + y**2)__, is that it is guaranteed not to overflow in the calculation, although it may set a range error if the result is too large. – ad absurdum Jul 14 '17 at 22:59