What I try to understand the following:
'Union' acts like like a variable and I can store value in it of different types.
What if in it stored value of type 'float', but I read it as 'short'?
Is there any ways how I can be sure about type of value I am going to retrieve from union ?
How can I deal with kind of cases ?
I saw a note somewhere, He talked about using 'enum' for cases like this, but there was no good enough explanation of why ?
Could you explain why is it useful/safe using 'unions' with 'enums', please ? Or show some examples.
Thanks in advance, Nick.
I believe it is a way of implementing tagged unions or sum types.
E.g. in C99 using an anonymous union
enum kind_en { knothing, kint, kfloat, kstring };
struct value_st {
enum kind_en kind;
union {
int n; // when kint
float f; // when kfloat
char* s; // when kstring
};
};
then e.g.
void print_value (struct value_st* v) {
if (!v) {puts("nil"); return; };
switch (v->kind) {
case knothing: puts("nothing"); return;
case kint: printf("int#%d", v->n); return;
case kfloat: printf("float#%g", v->f); return;
case kstring: printf("string'%s'", v->s); return;
default: abort();
}
}
struct value_st* make_int_value(int i) {
struct value_st* val = malloc(sizeof(struct value_st));
if (!val) { perror("malloc int value"); exit(EXIT_FAILURE); };
val->kind = kint;
val->n = i;
return val;
}
A much older example from the previous century is the XEvent type of Xlib
Notice that some programming languages have an easier way of supporting sum types. In Ocaml you need just
type val_t =
Knothing | Kint of int | Kfloat of float | Kstring of string;;
and most importantly you have pattern matching
Answers to your questions:
Yes, encode the type into a struct that contains the union:
union {
float f;
int i;
} my_union;
enum {
its_a_float,
its_an_int
} flavor;
struct {
flavor x;
my_union u;
} data_blob;
Not sure I grok your question, what sort of cases?
see above
It's useful for when you don't know the exact data you have/need at compile time and need to handle multiple flavors of the same logical data.
Add new filed of type enum and keep there information about current type
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef enum types_tag {
CHAR,
INT,
FLOAT
} types_t;
typedef union value_tag {
char c;
int i;
float f;
} value_t;
typedef struct store_tag {
types_t type;
value_t value;
} store_t;
void printValue(const store_t *o) {
switch (o->type) {
case CHAR:
printf("%c\n", o->value.c);
break;
case INT:
printf("%d\n", o->value.i);
break;
case FLOAT:
printf("%.3f", o->value.f);
break;
default:
exit(EXIT_FAILURE);
}
return;
}
void main() {
store_t a;
a.type = CHAR;
a.value.c = 'A';
printValue(&a);
a.type = FLOAT;
a.value.f = 10.45;
printValue(&a);
_getch();
}
Beside that, you can keep information just in bunch of memory and use void*
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef enum types_tag {
CHAR,
INT,
FLOAT
} types_t;
typedef struct store_tag {
types_t type;
void* value;
} store_t;
void printValue(const store_t *o) {
switch (o->type) {
case CHAR:
printf("%c\n", *(char*)(o->value));
break;
case INT:
printf("%d\n", *(int*)(o->value));
break;
case FLOAT:
printf("%.3f", *(float*)(o->value));
break;
default:
exit(EXIT_FAILURE);
}
return;
}
void main() {
store_t a;
a.type = CHAR;
a.value = malloc(1);
*((char*) a.value) = 'A';
printValue(&a);
free(a.value);
a.type = FLOAT;
a.value = malloc(sizeof(float));
*((float*) a.value) = 34.7;
printValue(&a);
free(a.value);
_getch();
}
and add some functions to hide creating and deleting variables.
Related
Is it possible to have a function in C return a 'dynamic' return type
example
printResult (NumOrChar());
void* NumOrChar(void) {
// return int or char
}
void printResult (void* input) {
if (isdigit(input)) {
printf("It's a number");
}
else {
printf("It's not a number");
}
Functions can certainly return void *. But that is a specific pointer type with properties that make it suitable for conveying pointers to objects of any type. It is not a general-purpose wildcard type. Moreover, it does not carry any kind of information about the actual type, if any, of the object to which it points, so there is no way to determine that type dynamically. A C++ programmer might describe this situation as C not providing any RTTI.
Instead, you can return a type that can convey objects of a variety of types, known in advance, with a mechanism to discriminate among those. For example,
union num_or_string {
struct { _Bool is_num; };
struct { _Bool _x1; int num; };
struct { _Bool _x2; char *string; };
};
union num_or_string NumOrChar(void) {
// return a union num_or_string containing an int or a char *
}
void printResult (union num_or_string) {
if (num_or_string.is_num) {
printf("It's a number: %d\n", num_or_string.num);
} else {
printf("It's a string: %s\n", num_or_string.string);
}
}
You can use _Generic in some circumstances
int func_int(int *p)
{
printf("%s\n", __FUNCTION__);
return 5; /* does not make too much sense */
}
float func_float(float *p)
{
printf("%s\n", __FUNCTION__);
return 5.0f; /* does not make too much sense */
}
double func_double(double *p)
{
printf("%s\n", __FUNCTION__);
return 5.0; /* does not make too much sense */
}
#define func(p) _Generic((p), \
int *: func_int, \
float *: func_float, \
double *: func_double)(p) \
Instead of having a block of ifs, one can use a structure of function pointers as a virtual table, including to_string. The following dynamically creates the Type, which can be Num or Letter.
#include <stddef.h> /* offsetof */
#include <stdio.h> /* [|s|sn]printf, fgets, stdin */
#include <stdlib.h> /* malloc, free, strtol */
#include <ctype.h> /* isdigit */
#include <errno.h>
#include <assert.h>
struct Type;
typedef void (*TypeToString)(const struct Type *const, char (*const)[32]);
typedef void (*TypeAction)(struct Type *const);
struct Type {
const struct TypeVt *vt;
};
/* Num extends Type. */
struct Num {
struct Type base;
int value;
};
static struct Num *num_upcast(struct Type *const type) {
return (struct Num *)(void *)((char *)type - offsetof(struct Num, base));
}
static const struct Num *const_num_upcast(const struct Type *const type) {
return (const struct Num *)(const void *)((const char *)type
- offsetof(struct Num, base));
}
static void num_to_string(const struct Type *const type, char (*const a)[32]) {
const struct Num *const num = const_num_upcast(type);
snprintf(*a, sizeof *a, "%d", num->value); /* C99. */
}
static void num_delete(struct Type *const type) {
struct Num *const num = num_upcast(type);
free(num);
}
/* Letter extends Type. */
struct Letter {
struct Type base;
char letter;
};
static struct Letter *letter_upcast(struct Type *const type) {
return (struct Letter *)(void *)((char *)type
- offsetof(struct Letter, base));
}
static const struct Letter *const_letter_upcast(const struct Type *const type) {
return (const struct Letter *)(const void *)((const char *)type
- offsetof(struct Letter, base));
}
static void letter_to_string(const struct Type *const t, char (*const a)[32]) {
const struct Letter *const letter = const_letter_upcast(t);
sprintf(*a, "%c", letter->letter);
}
static void letter_delete(struct Type *const type) {
struct Letter *const letter = letter_upcast(type);
free(letter);
}
static const struct TypeVt {
const char *name;
const TypeToString to_string;
const TypeAction delete;
} num_vt = { "num", &num_to_string, &num_delete },
letter_vt = { "char", &letter_to_string, &letter_delete };
static void type_to_string(const struct Type *const t, char (*const a)[32]) {
assert(t);
t->vt->to_string(t, a);
}
static void type_delete(struct Type *const t) {
assert(t);
t->vt->delete(t);
}
static struct Type *num(const int value) {
struct Num *num = malloc(sizeof *num);
if(!num) return 0;
num->base.vt = &num_vt;
num->value = value;
return &num->base;
}
static struct Type *letter(const char letter) {
struct Letter *l = malloc(sizeof *l);
if(!l) return 0;
l->base.vt = &letter_vt;
l->letter = letter;
return &l->base;
}
static struct Type *read_type(void) {
struct Type *type;
char buffer[64];
if(!fgets(buffer, sizeof buffer, stdin)) return 0;
if(isdigit(buffer[0])) {
long n;
errno = 0;
n = strtol(buffer, 0, 0);
if(errno) return 0;
type = num(n);
} else {
type = letter(buffer[0]);
}
return type;
}
int main(void) {
char a[32];
struct Type *type = 0;
int is_success = 0;
do {
if(!(type = read_type())) break;
type_to_string(type, &a);
printf("\"%s\" is of type %s.\n", a, type->vt->name);
is_success = 1;
} while(0); {
if(type) type_delete(type);
}
if(!is_success) return perror("Failure"), EXIT_FAILURE;
return EXIT_SUCCESS;
}
Probably overkill for your function, but as one has more types, this becomes increasingly attractive. One can consider a union of similar spaced types so that it could be allocated entirely on the stack.
$ bin/numorchar
524645 3456542563456
"524645" is of type num.
$ bin/numorchar
6245635724564357652654245634576
Failure: Result too large
$ bin/numorchar
ata gfddsgsdg
"a" is of type char.
$ bin/numorchar
"
" is of type char.
I guess you are speaking about the C# feature (according to my Google search).
In C, it's not possible unless doing it yourself (other answers show examples). It can be easy or hard depending of your needs. You should think about switching to another language if you really want this (they are sometimes called variants in them).
Hi I am currently attempting to learn C and I was wondering if there is a way to attain polymorphism in structures which contain a list of other different type of structures?
An example case of this is as such:
#include <stdlib.h>
#include <stdio.h>
typedef void (*update_t)(void *);
typedef struct entity entity_t;
typedef struct compA compA_t;
typedef struct compB compB_t;
struct compA{
update_t update;
};
struct compB{
update_t update;
};
struct entity{
update_t update;
int curSize;
void **components;
};
void compA_update(void *c){
printf("updating: componentA\n");
}
compA_t *compA_create(){
compA_t *c = malloc(sizeof(compA_t));
c->update = compA_update;
return c;
}
void compB_update(void *c){
printf("updating: componentB\n");
}
compB_t *compB_create(){
compB_t *c = malloc(sizeof(compB_t));
c->update = compB_update;
return c;
}
void entity_update(void *en){
entity_t *e = (entity_t *)en;
for(int i = 0; i < e->curSize; i++){
//would like to somehow update all the components with one line just iterating through the array but does not seem possible
}
return;
}
entity_t *entity_create(){
entity_t *e = malloc(sizeof(entity_t));
e->curSize = 0;
e->update = entity_update;
calloc(32, sizeof(void *));
return e;
}
void add_component(entity_t *e, void *c){
printf("%d\n", e->curSize);
e->components[e->curSize] = c;
e->curSize++;
return;
}
int main(void){
entity_t *e = entity_create();
compA_t *a = compA_create();
compB_t *b = compB_create();
add_component(e, a);
add_component(e, b);
e->update(e);
return 0;
}
So far my approach to this problem has been solved with void pointer arrays of a tuple structure which contains a enum type which identifies the structure as well as the structure itself and then in a potential update function a fairly ugly switch statement has to be implemented with a case for each specific type.
Is there a better way to do this? As the switch approach will get fairly crazy pretty fast if there are a lot of different types within the array. which means one must explicitly add cases for each type and every case does exactly the same thing, which in this case is call a function pointer named "update".
You can try data polymorphism instead of function pointer. That is, different data produce different behavior, using the same code.
For example, a simple polymorphic behavior:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
typedef const char* ccstr;
typedef struct animal_attr_t
{
bool is_body_segmented;
float gill_completeness;
float lung_completeness;
} animal_attr_t;
typedef struct species
{
ccstr name, kingdom, domain;
animal_attr_t animal_attr[0];
} species;
void initialize_species_base(species *this, ccstr name, ccstr kingdom, ccstr domain)
{
this->name = name;
this->kingdom = kingdom;
this->domain = domain;
}
void initialize_animal_attr(animal_attr_t *this, bool is_body_segmented, float gill_completenss, float lung_completeness)
{
this->is_body_segmented = is_body_segmented;
this->gill_completeness = gill_completenss;
this->lung_completeness = lung_completeness;
}
void print_species(species*);
int main(int argc, char *argv[])
{
species *yeast = calloc(sizeof(species), 1);
assert(yeast);
initialize_species_base(yeast, "yeast", "fungus", "eukaryote");
print_species(yeast);
species *dog = calloc(sizeof(species) + sizeof(animal_attr_t), 1);
assert(dog);
initialize_species_base(dog, "dog", "animal", "eukaryote");
initialize_animal_attr(dog->animal_attr, true, 0.0f, 1.0f);
print_species(dog);
free(yeast);
free(dog);
}
void print_species(species *this)
{
printf("name = %s, kingdom = %s, domain = %s",
this->name, this->kingdom, this->domain);
if (strcmp(this->kingdom, "animal") == 0) {
animal_attr_t *ani_attr = this->animal_attr;
printf(", has %s, %f completeness of gill, %f completeness of lung",
ani_attr->is_body_segmented ? "segmented body" : "unsegmented body",
ani_attr->gill_completeness, ani_attr->lung_completeness);
}
printf(".\n");
}
yeast and dog is 2 completely different types, yet with species it is expressed in an unified way and print_species has polymorphic behavior.
defined below struct:
enum DATATYPE {INT32, FLOAT, DOUBLE};
struct DATA{
enum DATATYPE type;
char buff[8];
};
struct DATA data; <==this data was set by other thread.
Then question is how to printf data easier?
I know the "switch" way.
switch (data.type) {
case INT32:
printf("%d", *(int*)buff);
break;
case FLOAT:
printf("%f", *(float*)buff);
break;
case DOUBLE:
printf("%lf", *(double*)buff);
break;
}
But if there are many DATATYPEs, it will be a hard way.
I am wondering is there some dynamic casting way in C ?
I mean is there any way like:
struct TYPEANDFORMAT {
enum DATATYPE type;
char fmt[10];
};
struct DATA{
enum DATATYPE type;
char buff[8];
};
struct TYPEANDFORMAT TypeFmt[] = {
{INT32, "%d"},
{FLOAT, "%f"},
{DOUBLE, "%lf"},
};
void printData (struct DATA *data)
{
printf(TypeFmt[data->type].fmt, xxxx); <===xxxx is the issue
}
I guess there should be some MACRO could work here.
What do you think about using a union structure instead of a struct? That maybe would be better in your case.
http://en.wikipedia.org/wiki/Union_type#Difference_between_Union_and_Structure
Define the union:
enum DATATYPE {INT32, FLOAT, DOUBLE};
typedef union myunion
{
double D;
float F;
int I;
}MYUNION;
struct DATA{
enum DATATYPE type;
MYUNION d;
};
and after
switch (data.type) {
case INT32:
printf("%d", data.d.I);
break;
case FLOAT:
printf("%f", data.d.F);
break;
case DOUBLE:
printf("%lf", data.d.D);
break;
}
How can I return a string or a number within one function.
Such as:
int main()
{
printf("%s",rawinput("What is your name: ", "s"));
printf("%d", rawinput("How old are you: ", "n"));
}
([int] or [char *]) rawinput(char *message, char *type)
{
if(!strcmp(type,"n")){
int value;
scanf("%d",&value);
return value;}
else if(!strcmp(type, "s")){
char *value[1024];
fgets(value,1024,stdin);
return value;}
}
Note that the way of defining the rawinput function changes based.
Do not do that. There is a way, but it is a bad practice, and you shouldn't use it. Here is a better option for that:
typedef union RAWINPUT_UNION
{
char *string;
int integer;
}RAWINPUT;
RAWINPUT rawinput(char *message, char *type)
{
char *resultstring
int resultinteger;
RAWINPUT ri;
// Blah blah blah some code here.
if(type[0] == 's')
ri.string = resultstring;
else if(type[0] == 'i')
ri.integer = resultinteger;
return ri;
}
And the bad way is: You can perform integer arithmetic on a pointer, and store variables in it, because pointers are de facto integers, just with an addictional layer of abstraction in the compiler.
Given that the return value needs to be a char * in one printf("%s",... and an int int printf("%d", ..., the return type of the function should match the format specifier and be different between calls to avoid undefined behavior (UB). Let's use:
typedef struct {
union {
char *s;
int i;
} u;
char type;
} raw_t;
raw_t rawinput(const char *message, char type) {
raw_t r;
printf("%s", message);
r.type = type;
switch (type) {
case 'n':
if (1 != scanf("%d", &r.u.i)) {
; // handle error;
}
break;
case 's': {
char tmp[1024];
if (1 != scanf("%1023s", tmp)) {
; // handle error;
}
r.u.s = strdup(tmp);
break;
}
default:
; // handle error;
}
return r;
}
int main() {
printf("%s\n", rawinput("What is your name: ", 's').u.s); // Note .u.s
printf("%d\n", rawinput("How old are you: " , 'n').u.i); // Note .u.i
return 0;
}
Take care of the memory leak in printf("%s....
I have implemented a linked list in C (not C++) that stores pointers to data. I would like to have multiple declarations for its functions (to provide type safety), but have each of them link to the same definition (because there is no actual difference between pointers to different data types, so using the same code reduces space).
Does anyone have any ideas on how to achieve this (or any better ways to do it)? A portable solution is obviously best, but I really just need something that works in GCC.
I believe you might be able to achieve this using typedefs for function prototypes and
casting the generic solution (which deals in void*s) to the specific prototype. This should be safe for compilation because all pointers would be the same size.
Consider this example:
do_something.h:
typedef void (*do_something_with_int_t)(int *i);
extern do_something_with_int_t do_something_with_int;
typedef void (*do_something_with_string_t)(char *s);
extern do_something_with_string_t do_something_with_string;
do_something.c
#include "do_something.h"
void do_something_generic(void* p) {
// Do something generic with p
}
do_something_with_int_t do_something_with_int =
(do_something_with_int_t)do_something_generic;
do_something_with_string_t do_something_with_string =
(do_something_with_string_t)do_something_generic;
As long as do_something_generic is truly datatype-agnostic (i.e. it really doesn't matter what p points to) then this would be OK.
If it's C (not C++), then the following will work just fine. You can adapt the concept to your needs.
tt.h
typedef struct {
int ii;
} Type_1;
typedef struct {
int ii;
} Type_2;
int foo_1(Type_1* ptr) __attribute__((alias("foo")));
int foo_2(Type_2* ptr) __attribute__((alias("foo")));
tt.c
#include <stdio.h>
#include "tt.h"
int main() {
Type_1 t_1;
Type_2 t_2;
foo_1(&t_1);
foo_2(&t_2);
}
int foo(void* arg) {
printf("foo: %p\n", arg);
}
#include <stdio.h>
struct common_type {
int type;
};
struct type1 {
int type;
int value;
};
struct type2 {
int type;
char* p;
};
int func(void *para) {
switch (((struct common_type*)para)->type) {
case 1:
printf("type1,value:%d\n",((struct type1*)para)->value);
break;
case 2:
printf("type2,content:%s\n",((struct type2*)para)->p);
break;
}
}
int main() {
char *s = "word";
struct type1 t1 = {1,1};
struct type2 t2;
t2.type = 2;
t2.p = s;
func((void*)&t1);
func((void*)&t2);
}