简体   繁体   中英

Setting Variables in a C struct just like in a C# class constructor

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.

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);
}

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 };

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM