C enum Printing error? - c

In College we had to write a program with structs, enums and unions to display a date,
like 1.September 2014.
I had some problems with printing an enum. I found some solutions in this forum and finally I've got no console errors anymore. But Everytime I try to run my Program it crashes.
Maybe someone of you knwos what's causing the crash:
#include <stdio.h>
enum Monate{JANUAR = 1,
FEBRUAR = 2,
MAERZ = 3,
APRIL = 4,
MAI = 5,
JUNI = 6,
JULI = 7,
AUGUST = 8,
SEPTEMBER = 9,
OKTOBER = 10,
NOVEMBER = 11,
DEZEMBER = 12 };
union Monat{
enum Monate alsMonat;
char alsZahl;
char alsString[10];
};
struct Datum {
char tag;
union Monat monat;
short jahr;
};
const char* welcherMonat(enum Monate meinMonat){
switch(meinMonat){
case JANUAR: return"Januar";
break;
case FEBRUAR: return"Februar";
break;
case MAERZ: return"Maerz";
break;
case APRIL: return"April";
break;
case MAI: return"Mai";
break;
case JUNI: return"Juni";
break;
case JULI: return"Juli";
break;
case AUGUST: return"August";
break;
case SEPTEMBER: return"September";
break;
case OKTOBER: return"Oktober";
break;
case NOVEMBER: return"November";
break;
case DEZEMBER: return"Dezember";
break;
}
}
void ausgabe(struct Datum *datum){
char month[10]=" ";
printf("Tag: %c\n",(*datum).tag);
enum Monate monat2=(*datum).monat.alsMonat;
printf("Monat: %s\n",welcherMonat(monat2));
printf("Jahr: %d\n\n",(*datum).jahr);
}
int main(int argc, char** argv){
struct Datum Geburtstag = {'3',AUGUST,1995};
struct Datum Heute = {'3','12',2014};
struct Datum Millenium = {'1',1,2000};
ausgabe(&Geburtstag);
ausgabe(&Heute);
ausgabe(&Millenium);
return 0;
}

Use GDB. It is the Gnu DeBugger. Compile your code with the -g option enabled, and it will include all of the proper debugging symbols. You can then use GDB to put a manual break in the program and step through it one line at a time, look at variables, and see exactly where it is crashing.

How can you have a multi-character char like this:
struct Datum Heute = {'3','12',2014};
Doesn't your compiler throw a warning for this? It should ideally

It seems like I overlooked the MultiCharacter warning...
When I choose a one-character month it still freezes at the second print, when I want to print the date by using a char as month. The other two types of printing the month(by enum) work totally fine.
Our task was to print three different dates by using all three kinds of month-printing.
I think I know the Problem:
enum Monate monat2=(*datum).monat.alsMonat;
printf("Monat: %s\n",welcherMonat(monat2));
when I give the function a char instead of an enum, "monat2" is empty.
But how could I check whether I give him a char or an enum?

Related

Assigning a table of values without changing variable name or making fancy code

This is a sample of code I'm dealing with.
switch(n){
case 1:
char tcol[4][100]={"Canadian Order","Achat Francais","china"};
char trow[7][100]={"Item","Price","Qty","Total","Tax","Grand total"};
Htable(trow,tcol,7,4,"");
break;
case 2:
char tcol[3][100]={"Other column 1","2nd column"};
char trow[4][100]={"1st row","2nd row","Row 3"};
Htable(trow,tcol,4,3,"");
break;
case n:
...
}
Basically I'm creating a function Htable that takes the row and column names for an HTML table and the 3rd and 4th argument is the number of rows and columns.
The problem I have is the compiler thinks I'm redefining the array even though each definition is accessible only once from a switch branch. Here's the errors:
./html2.c:118: error: redefinition of ‘tcol’
./html2.c:110: error: previous definition of ‘tcol’ was here
./html2.c:119: error: conflicting types for ‘trow’
./html2.c:111: error: previous declaration of ‘trow’ was here
And that keeps happening for each block of code I have. The only partial solution I could come up with is the following:
char tcol[1][4][100]={"Canadian Order","Achat Francais","china"};
char trow[1][7][100]={"Item","Price","Qty","Total","Tax","Grand total"};
char trow[2][4][100]={"1st row","2nd row","Row 3"};
char tcol[2][4][100]={"Other column 1","2nd column"};
switch(n){
case 1:
Htable(trow[1],tcol[1],7,4,"");
break;
case 2:
Htable(trow[2],tcol[2],4,3,"");
break;
case n:
...
}
Is there a simple way to do this where the C compiler accepts it without having to add fancy code to separate the strings?
Is there a simple way to do this where the C compiler accepts it without having to add fancy code to separate the strings?
Declare objects tcol, trow in separate sub-blocks. #WhozCraig
void foo(int n) {
switch (n) {
case 1: { // add {
char tcol[4][100] = {"Canadian Order", "Achat Francais", "china"};
char trow[7][100] =
{"Item", "Price", "Qty", "Total", "Tax", "Grand total"};
Htable(trow, tcol, 7, 4, "");
break;
} // add }
case 2: { // add {
char tcol[3][100] = {"Other column 1", "2nd column"};
char trow[4][100] = {"1st row", "2nd row", "Row 3"};
Htable(trow, tcol, 4, 3, "");
break;
} // add }
}
}
Note that the lifetime of tcol is only to the block. Make static to last always. Yet I suspect, depending on larger code, a new approach may be needed - something fancy.
Size optimization aside: consider forming an array of pointers to strings.
// char tcol[4][100] = {"Canadian Order", "Achat Francais", "china"};
const char *tcol[] = {"Canadian Order", "Achat Francais", "china", NULL};
Changes also needed to Htable().

Get enum name associated with a int val in C. Avoid typecast from int to enum

How can I get enum name associated with a int val.
I have following code:
#include<stdio.h>
#include<stdlib.h>
typedef enum _MyID{
id1 = 1,
id2 = 2,
id3 = 3,
}MyID;
MyID get_idname(int id_val)
{
switch(id_val){
case 1:
return id1;
case 2:
return id2;
case 3:
return id3;
default: //checks for invalid ID
return -1;
}
}
int main()
{
int val1 = 1;
int val2 = 2;
MyID new_id1 = (MyID)(val1|val2);
MyID new_id2 = (MyID)(4);
MyID new_id3 = get_idname(3);
MyID new_id4 = get_idname(4);
printf("id is new_id1 %d, new_id2 %d, new_id3 %d, new_id4 %d \n", new_id1, new_id2, new_id3, new_id4);
return 0;
}
The above code outputs the following:
id is new_id1 3, new_id2 4, new_id3 3, new_id4 -1
Clearly, typecasting int to enum is dangerous. One way to resolve this is to use a function (like in the above) with switch statement to catch the invalid value passed. The issue with this is, I have really big enum with 100's of values so writing switch case for each enum is hectic task and not scalable approach. I would like to know if there is any efficient solution for the same.
If enums names is patterned (as in you sample), you can use macro for fast cases populating. For example, 101 cases can be simple populated
#define CASE(N) case N: return id##N;
#define DOZEN_CASES(N) CASE(N##0) CASE(N##1) CASE(N##2) CASE(N##3) CASE(N##4) CASE(N##5)\
CASE(N##6) CASE(N##7) CASE(N##8) CASE(N##9)
MyID get_idname(int id_val)
{
switch (id_val) {
DOZEN_CASES() DOZEN_CASES(1)
DOZEN_CASES(2) DOZEN_CASES(3)
DOZEN_CASES(4) DOZEN_CASES(5)
DOZEN_CASES(6) DOZEN_CASES(7)
DOZEN_CASES(8) DOZEN_CASES(9)
CASE(100) CASE(101)
default: //checks for invalid ID
return -1;
}
}
Underscore-beginning globals and especially underscore+uppercase-letter-beginning identifiers are reserved. If you must have both the tag and the typedef, just do typedef MyID { ...} MyID;.
As for your problem, if the enum constants are contiguously increasing, you can simply do:
typedef enum MyID{
idERR=-1,
id1 = 1,
id2 = 2,
id3 = 3,
//...
idMAX
}MyID;
MyID get_idname(int id_val) { return (id_val>0&&id_val<idMAX)?id_val:-1; }
Other than that there's always code generation. (If writing the program is tedious, write a program to write the program).
If you intend to assign -1 into the enum, you should probably make an enumerator constant for it too. Otherwise, the compiler might make MyID an unsigned type which might lead to a nasty surprise if you then ever do if (0>my_id).

Verify that all set values of an enum are distinct

I just recently found out that when setting values of variables of an enum, several variables can have the same value. For example, the following code is perfectly correct:
enum my_enum
{
A = 3,
B = 4,
C = 3,
D = 5
};
However, in my framework, I have to set manualy each variable, since it is used to communicate error codes to other systems. I cannot change the value of an error code without asking for the other teams to modify it as well.
I regrouped all error codes into an enumeration to be sure we do not reuse the same error code for different reasons (which was the case before). But now, nothing stops anyone to reuse the same value for different errors.
Is there a way I can make the compiler return an error if I assign the same value to different names in my enum?
I can compile with either gcc or clang.
A switch statement cannot have two cases with the same value. So you can have a switch somewhere. Make it with no default: case and gcc will warn you that a member of the enum is not handled in the switch statement if you add a new value. If two values of the enum are the same, compilation will fail.
Some examples:
typedef enum {
ERR_NONE = 0,
ERR_SAME = 0
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_SAME:
break;
}
return 0;
}
with gcc -Wall switch.c gives:
switch.c: In function 'main':
switch.c:16:9: error: duplicate case value
case ERR_SAME:
^
switch.c:13:9: error: previously used here
case ERR_NONE:
^
and...
typedef enum {
ERR_NONE = 0,
ERR_NEXT,
ERR_MISSING,
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_NEXT:
break;
}
return 0;
}
with gcc -Wall switch-missing.c gives:
switch-missing.c: In function 'main':
switch-missing.c:12:5: warning: enumeration value 'ERR_MISSING' not handled in switch [-Wswitch]
switch( e )
^

how can I make a char buffer acting as a file?

I'm having trouble converting a char buffer in a FILE* (if this is even possible, of course!).
I have an enumeration defines as such:
typedef enum SchemaType{
SCHEMA_INT,
SCHEMA_REAL,
SCHEMA_STRING,
SCHEMA_BOOLEAN,
SCHEMA_CHAR,
SCHEMA_SIMPLE,
SCHEMA_RECORD,
SCHEMA_ARRAY
} SchemaType;
I have a perfectly functioning function that prints out the enumeration itself (for debugging purposes):
void printSchemaType(FILE* f,SchemaType schemaType){
switch (schemaType){
case SCHEMA_INT: fprintf(f,"int"); break;
case SCHEMA_ARRAY: fprintf(f,"array"); break;
case SCHEMA_BOOLEAN: fprintf(f,"boolean"); break;
case SCHEMA_CHAR: fprintf(f,"char"); break;
case SCHEMA_REAL: fprintf(f,"real"); break;
case SCHEMA_RECORD: fprintf(f,"record"); break;
case SCHEMA_STRING: fprintf(f,"string"); break;
}
}
Now the problem: I need to use the string printed out by fprintf (i.e. "int", "char", "real", ex cetera) as key in an hashtable; for this purpose i would like to store the printed string of printSchemaType() inside a variable, maybe by using sprintf:
char buffer[25];
sprintf(buffer,"%s",printSchemaType_output);
The problem is that I need to get the function output inside a variable! I know I could:
create a new function storeSchemaTypeInsideBuffer(const char* buffer,SchemaType type); with a switch ... case but i would prefer not to because I don't want redundant code for a little thing like this;
change the prototype of "printSchemaType" into
void printSchemaType(const char* buffer,SchemaType schemaType)
but I would prefer not to because there are other functions like printSchemaType with a similar prototype (printTYPE(FILE* f, TYPE typevariable)) and changing its prototype would create a differentiation of prototypes between this only function and the other ones;
The solution I was thinking is to transform a char buffer into a FILE* variable: in this way I would be able to do something like this:
SchemaType=SCHEMA_INT;
char buffer[25];
FILE* bufferActingAsAFile=make_buffer_acts_as_a_File(buffer);
fprintf(bufferActingAsAFile,type); //now in the buffer there is stored "int"
Is something like this even possible in C? If yes, how can I do that?
Not what you asked for, but I would rewrite your printSchemaType function.
Create a new function called SchemaTypeStr (or some other name that fits your naming scheme) like this:
const char* SchemaTypeStr(enum SchemaType type) {
switch(type) {
case SCHEMA_INT: return "int"; break;
case SCHEMA_ARRAY: return "array"; break;
case SCHEMA_BOOLEAN: return "boolean"; break;
case SCHEMA_CHAR: return "char"; break;
case SCHEMA_REAL: return "real"; break;
case SCHEMA_RECORD: return "record"; break;
case SCHEMA_STRING: return "string"; break;
default: abort();
}
}
void printSchemaType(FILE* f,SchemaType schemaType) {
fputs(SchemaTypeStr(schemaType), f);
}
There doesn't seem to be a portable solution. For linux, you can use fmemopen, but for Windows you'll need to use CreateFile, CreateFileMapping and MapViewOfFile.
See similar question here.

Constant integral expression required error

I am writing code for AVR ATmega32-A microcontroller. I am using switch case as shown below.
unsigned char Command;
unsigned int Param;
void runCom(void){
switch(Command){
case(NO_COM):
Command = 0;
break;
case(INF):
printf("\r\n\r\n");
printf("university\r\n");
printf("sweden\r\n");
printf("Ver. 1.0A\r\n");
Command = 0;
break;
case (DB):
Command = 0;
break;
case(CLEARM):
Command = 0;
break;
default:
Command = 0;
break;
}
}
the above code is working but now i want to add one more case in that switch like as shown below.
unsigned char Command, Command1;
unsigned int Param;
void runCom(void){
switch(Command){
case(NO_COM):
Command = 0;
break;
case(INF):
printf("\r\n\r\n");
printf("university\r\n");
printf("sweden\r\n");
printf("Ver. 1.0A\r\n");
Command = 0;
break;
case (DB):
Command = 0;
break;
case(ADC):
printf("ADC Value",ReadAd());
printf("Enter Amplification stage");
switch(Command1){
case(stage1):
PORTC=0x00;
DDRC=0xC0;
printf("ADC Value",ReadAd());
Command1 = 0;
break;
case(stage2):
PORTC=0x00;
DDRC=0x03;
printf("ADC Value",ReadAd());
Command1 = 0;
break;
}
Command = 0;
break;
case(MEM):
Command = 0;
break;
case(CLEARM):
Command = 0;
break;
default:
Command = 0;
break;
}
}
I am getting error like
undefind symbol 'ADC'
undefind symbol 'stage1'
undefind symbol 'stage2'
then i have declared like this
unsigned char Command, ADC, Command1, stage1, stage2;
unsigned int Param;
now i am getting error like
constant integral expression required at line case(ADC)
constant integral expression required at line case(stage1)
constant integral expression required at line case(stage2)
so please can any one suggest me how to overcome this error. I haven't declared WGP, WGF, INF any where but I am not getting "undefined symbol of WGF, WGP, INF. why this error occurring for ADC only. i have fallowed same switch case rules as i used before. any suggestions appreciated.
Thanks in advance.
The values in a case needs to be constants or literals.
If you look up e.g. WGP you will see that it's most likely a #define'd literal. Do the same for your new values.
The values you use in the cases of a switch statement must be compile-time constants. That is, they must have fixed values that are known to to the compiler at compile time.
There are four main ways to do this.
You can use a constant literal (a number).
case 42:
Note that using unnamed values ("magic numbers") isn't recommended because it doesn't document the code in any way, and makes the code fragile (what if you need to change the value to 43 in five different places and forget one?)
You can use a preprocessor constant.
#define COMMAND_CODE 42
...
case COMMAND_CODE:
That's better because if you need to changet the command code value to 43 you only have to change the #define (which should only occur once, in a header file).
You can use an enum.
typedef enum { COMMAND_ON=42, COMMAND_OFF=2, COMMAND RESET=77 } command_codes:
...
case COMMAND_ON:
In C++, if your compiler is reasonably modern, you can use a constant:
const int magic_number = 42;
case magic_number:
(Note that the switch value shown in a case statement does NOT need to have parentheses around it.)
From the code you have shown, it seems that you have defined Command, ADC, etc., as variables (rather than as constants). In this case the compiler can't know what value those variables will have at execution time when it compiles the code. The language specifies that case values must be known at compile time so that the compiler can generate fast code (faster then a whole series of if ... else if ... else if statements).

Resources