C++ Enum to String Switch Not Working - c++

I am instantiating an object with a few enum types and trying to set some string members based on those enum types. However, when I am debugging and step though, the switch used to set the strings hits every case, and each string gets set to the last case for each enum type.
enum Number {
one,
two,
three
};
enum Color {
purple,
red,
green
};
enum Shading {
solid,
striped,
outlined
};
enum Shape {
oval,
squiggle,
diamond
};
Card::Card(Number num, Color colour, Shading shade, Shape shaper) {
number_ = num;
color_ = colour;
shading_ = shade;
shape_ = shaper;
setStrings();
}
void Card::setStrings() {
switch (number_) {
case one:
number_string = "one";
case two:
number_string = "two";
case three:
number_string = "three";
}
switch(color_) {
case purple:
color_string = "purple";
case red:
color_string = "red";
case green:
color_string = "green";
}
switch (shading_) {
case solid:
shading_string = "solid";
case striped:
shading_string = "striped";
case outlined:
shading_string = "outlined";
}
switch (shape_) {
case oval:
shape_string = "oval";
case squiggle:
shape_string = "squiggle";
case diamond:
shape_string = "diamond";
}
}
Every card I instantiate using the overloaded constructor has number_string = "three", color_string = "green", shading_string = "outlined", and shape_string = "diamond".

You need to use break for switch statements' case clause else it is a fall through. Here is an example and details for you. https://10hash.com/c/cf/#idm45440468325552
#include <stdio.h>
int main()
{
int i = 65;
switch(i)
{
case 'A':
printf("Value of i is 'A'.\n");
break;
case 'B':
printf("Value of i is 'B'.\n");
break;
default:
break;
}
return 0;
}

Your switch-case is not correct. You need to put a break after every case for your solution otherwise it will go into every case until it is finished and not break when it hits the case you want.

Related

how to only indent brackets after case labels using clang-format

I wanna a style that only indent brackets after case labels, while keeping case label not indented.
this is what I want:
switch(a)
{
case 1:
{
do_some_thing();
}
break;
}
I find an option IndentCaseLabels, but it will the whole things include the case label, neither true or false isn't what I want
true:
switch(a)
{
case 1:
{
do_some_thing();
}
break;
}
false:
switch(a)
{
case 1:
{
do_some_thing();
}
break;
}
Is this style possible in clang-format? If is, how could I Configure it?
It's just immediate above one you found in the manual.
IndentCaseBlocks: true
Indent case label blocks one level from the case label.
false: true:
switch (fool) { vs. switch (fool) {
case 1: { case 1:
bar(); {
} break; bar();
default: { }
plop(); break;
} default:
} {
plop();
}

Defining variables esp32

i am trying to figure out a way in esp32 to have (a list) for lack of better terms, that i could call upon as a variable input. I have a void playwav(); function. I want to use a global variable to define the file that should be played. ie playwav('alarm'). I had a case switch setup but was using the a b c method. As my code is growing (next step is going to add 71 new wav files), i am quickly realizing that method will no longer work. I have been told to do an array but for the life of me no matter what ive read i just cant grasp how to do it nor call upon the files by name. Does anyone have advice on what i should do? Any help is much appreciated.
This is what i currently have.
void playWAV (char effect, int bg1248_general_volume)
{
Serial.println("Entered playWAV");
switch (effect)
{
case 'a':
file = new AudioFileSourceSD("/wav/alarm.wav");
break;
case 'b':
file = new AudioFileSourceSD("/wav/alarmhigh.wav");
break;
case 'c':
file = new AudioFileSourceSD("/wav/alarmlow.wav");
break;
case 'd':
file = new AudioFileSourceSD("/wav/error.wav");
break;
case 'e':
file = new AudioFileSourceSD("/wav/error1.wav");
break;
case 'f':
file = new AudioFileSourceSD("/wav/noread.wav");
break;
case 'g':
file = new AudioFileSourceSD("/wav/noreadings.wav");
break;
case 'h':
file = new AudioFileSourceSD("/wav/normalrange.wav");
break;
case 'i':
file = new AudioFileSourceSD("/wav/warning.wav");
break;
case 'j':
file = new AudioFileSourceSD("/wav/warninghigh.wav");
break;
case 'k':
file = new AudioFileSourceSD("/wav/warninglow.wav");
break;
case 'l':
file = new AudioFileSourceSD("/wav/startup.wav");
break;
case 'm':
file = new AudioFileSourceSD("/wav/startup.wav");
break;
case 'n':
file = new AudioFileSourceSD("/wav/update.wav");
break;
case 'o':
file = new AudioFileSourceSD("/wav/startup_dev.wav");
}
float volumeGain = ((float)bg1248_general_volume / 100.0) * 39.0;
Serial.print("volumeGain:");
Serial.println(volumeGain);
id3 = new AudioFileSourceID3(file);
out = new AudioOutputI2S(0, 0); // Output to builtInDAC
out->SetPinout(12, 0, 2);
out->SetOutputModeMono(true);
out->SetGain(volumeGain);
wav = new AudioGeneratorWAV();
wav->begin(id3, out);
However because I used the alphabet im going to run out of cases very very soon. I want to be able to call for a specific wav file anywhere in the project preferably like playWAV(filename) or something similar.
I call the function(file) like this (example condition)
if((ns->sensSgv<=cfg.snd_alarm) && (ns->sensSgv>=0.1)) {
// red alarm state
// M5.Lcd.fillRect(110, 220, 100, 20, TFT_RED);
Serial.println("ALARM LOW");
M5.Lcd.fillRect(0, 220, 320, 20, TFT_RED);
M5.Lcd.setTextColor(TFT_BLACK, TFT_RED);
int stw=M5.Lcd.textWidth(tmpStr);
M5.Lcd.drawString(tmpStr, 159-stw/2, 220, GFXFF);
if( (alarmDifSec>cfg.alarm_repeat*60) && (snoozeRemaining<=0) ) {
playWAV('a', 100);
'a'=case 100 = volume.
Alan, this is what I currently had in my enum, i was following a tutorial but doubt i did it right. even if i did i was getting errors saying i had duplicate cases when i don't.
EDIT:
The condition is set using this:
if((ns->sensSgv<=cfg.snd_alarm) && (ns->sensSgv>=0.1))
and if you notice at the bottom there is:
if( (alarmDifSec>cfg.alarm_repeat*60) && (snoozeRemaining<=0) ) {
playWAV('a', 100);
The a corelates to the case A in the switch case. shown above. currently all the places that use the playWAV function are manually specified.
My understanding was using the alphabets in switch case will ran out soon because of large no. of files (>26). So, I implemented the logic using enum first and below is the complete code.
#include<stdio.h>
enum soundEffects {
alarm,
alarm_high,
alarm_low,
Dev_startup,
error,
error1,
noread,
noreadings,
normalrange,
startup,
startup_dev,
update,
warning,
warning_high,
warning_low,
};
void playWav (enum soundEffects effect, int paci_volume)
{
//Serial.println("Entered paciplay_day");
//printf("Entered paciplay_day\n");
switch (effect)
{
case alarm:
//file = new AudioFileSourceSD("/wav/alarm.wav");
printf("/wav/alarm.wav\n");
break;
case alarm_high:
//file = new AudioFileSourceSD("/wav/alarmhigh.wav");
printf("/wav/alarmhigh.wav\n");
break;
case alarm_low:
//file = new AudioFileSourceSD("/wav/alarmlow.wav");
printf("/wav/alarmlow.wav\n");
break;
case error:
//file = new AudioFileSourceSD("/wav/error.wav");
printf("/wav/error.wav\n");
break;
case error1:
//file = new AudioFileSourceSD("/wav/error1.wav");
printf("/wav/error1.wav\n");
break;
case noread:
//file = new AudioFileSourceSD("/wav/noread.wav");
printf("/wav/noread.wav\n");
break;
case noreadings:
//file = new AudioFileSourceSD("/wav/noreadings.wav");
printf("/wav/noreadings.wav\n");
break;
case normalrange:
//file = new AudioFileSourceSD("/wav/normalrange.wav");
printf("/wav/normalrange.wav\n");
break;
case warning:
//file = new AudioFileSourceSD("/wav/warning.wav");
printf("/wav/warning.wav\n");
break;
case warning_high:
//file = new AudioFileSourceSD("/wav/warninghigh.wav");
printf("/wav/warninghigh.wav\n");
break;
case warning_low:
//file = new AudioFileSourceSD("/wav/warninglow.wav");
printf("/wav/warninglow.wav\n");
break;
case startup:
//file = new AudioFileSourceSD("/wav/startup.wav");
printf("/wav/startup.wav\n");
break;
case update:
//file = new AudioFileSourceSD("/wav/update.wav");
printf("/wav/update.wav\n");
break;
}
}
int main()
{
//below are the 3 ways of calling your playWav() function
//1 - using direct numbers
//this will throw compilation error when compiled using cpp compilers
for (int i = 0; i<14; i++)
{
printf("enum value: %d\n", i);
playWav(i, 50);
}
//2 - directly calling using the enum
playWav(startup, 100);
//3 - Just another way of calling
enum soundEffects sound;
sound = error;
playWav(sound, 100);
return 0;
}
Also, I implemented this same logic using double array's. Please do find it below. This uses the name of the file as a parameter so altogether we can eliminate the use of switch statement.
#include<stdio.h>
void playWav (const char *filename, int paci_volume)
{
//Serial.println("Entered paciplay_day");
printf("Entered paciplay_day\n");
//file = new AudioFileSourceSD("/wav/update.wav");
printf("/wav/%s\n", filename);
}
int main()
{
const char list_of_files[][25] = { "startup.wav", "update.wav", "warning.wav", "alarm.wav" };
for (int i = 0; i<4; i++)
{
printf("name: %s\n", list_of_files[i]);
playWav(list_of_files[i], 50);
}
return 0;
}
Please omit my printf statements which I used for debugging. I hope this is useful.

Why does my switch/case default when using enums?

I have the following switch/case statement in Arduino 1.8.7 where the variable led is an integer:
switch (led) {
case ALL: {
/* do stuff */
break;
}
case LED1: {
/* do stuff */
break;
}
case LED2: {
/* do stuff */
break;
}
case LED3: {
/* do stuff */
break;
}
case LED4: {
/* do stuff */
break;
}
default: {
break;
}
}
I also have the following enum:
enum LED_References_e
{
ALL = 0,
LED1 = 1,
LED2 = 2,
LED3 = 3,
LED4 = 4
};
When using the enumerated values as cases to the statement, the statement always hits the default clause. If I substitute the enumerated values for the integers that they represent (i.e.case 0: ... case 1: ...) then the statement functions as expected.
I have tried, when using the enumerated values within the statement, to reference the enumerator as the value that the switch is performed on:
switch ((LED_References_e)led)
But this also defaults every time.
I am using another enumerator within my program and this functions correctly, however it is conditionally tested using if/else as opposed to switch/case.
My question is twofold:
Why does the switch/case statement seemingly not work with enumerated values?
What fundamental difference am I missing between if/else and switch/case?
Assuming Max Langhof is correct and there are other names ALL, LED1, etc... in scope at the switch so that the LED_References_e ones are shadowed, this should help:
I'm not 100% certain about the differences between standard C++ and Arduino C++, but you should be able to do the following:
enum LED_References_e
{
ALL = 0,
LED1 = 1,
LED2 = 2,
LED3 = 3,
LED4 = 4
};
switch (led) {
case LED_References_e::ALL: {
/* do stuff */
break;
}
case LED_References_e::LED1: {
/* do stuff */
break;
}
case LED_References_e::LED2: {
/* do stuff */
break;
}
case LED_References_e::LED3: {
/* do stuff */
break;
}
case LED_References_e::LED4: {
/* do stuff */
break;
}
default: {
break;
}
}
What this does is it tells the compiler you explicitly want LED1...LED4 from the LED_References_e enum.
If there are other LEDxes in the same scope, this should disambiguate.

Capping the value

I have a small script that defines the casting time for all classes in this minor project im working on however i have a few issues.
I want to place a cap on the max value however i'm getting errors!
this is the function i was referring to.
void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
{
float oldRating = m_baseRatingValue[combatRating];
m_baseRatingValue[combatRating] += (apply ? value : -value);
// explicit affected values
float const multiplier = GetRatingMultiplier(combatRating);
float const oldVal = oldRating * multiplier;
float const newVal = m_baseRatingValue[combatRating] * multiplier;
switch (combatRating)
{
case CR_HASTE_MELEE:
ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true);
ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true);
break;
case CR_HASTE_RANGED:
ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true);
break;
case CR_HASTE_SPELL:
//ApplyCastTimePercentMod(oldVal, false);
//ApplyCastTimePercentMod(newVal, true);
break;
default:
break;
}
UpdateRating(combatRating);
}
void Player::UpdateRating(CombatRating cr)
{
int32 amount = m_baseRatingValue[cr];
// Apply bonus from SPELL_AURA_MOD_RATING_FROM_STAT
// stat used stored in miscValueB for this aura
AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
for (AuraEffect const* aurEff : modRatingFromStat)
if (aurEff->GetMiscValue() & (1 << cr))
amount += int32(CalculatePct(GetStat(Stats(aurEff->GetMiscValueB())), aurEff->GetAmount()));
if (amount < 0)
amount = 0;
SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
bool affectStats = CanModifyStats();
switch (cr)
{
case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_DEFENSE_SKILL:
UpdateDefenseBonusesMod();
break;
case CR_DODGE:
UpdateDodgePercentage();
break;
case CR_PARRY:
UpdateParryPercentage();
break;
case CR_BLOCK:
UpdateBlockPercentage();
break;
case CR_HIT_MELEE:
UpdateMeleeHitChances();
break;
case CR_HIT_RANGED:
UpdateRangedHitChances();
break;
case CR_HIT_SPELL:
UpdateSpellHitChances();
break;
case CR_CRIT_MELEE:
if (affectStats)
{
UpdateCritPercentage(BASE_ATTACK);
UpdateCritPercentage(OFF_ATTACK);
}
break;
case CR_CRIT_RANGED:
if (affectStats)
UpdateCritPercentage(RANGED_ATTACK);
break;
case CR_CRIT_SPELL:
if (affectStats)
UpdateAllSpellCritChances();
break;
case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc
case CR_HIT_TAKEN_RANGED:
break;
case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult
break;
case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit)
case CR_CRIT_TAKEN_RANGED:
break;
case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit)
break;
case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod
case CR_HASTE_RANGED:
case CR_HASTE_SPELL:
break;
case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_WEAPON_SKILL_OFFHAND:
case CR_WEAPON_SKILL_RANGED:
break;
case CR_EXPERTISE:
if (affectStats)
{
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
}
break;
case CR_ARMOR_PENETRATION:
if (affectStats)
UpdateArmorPenetration(amount);
break;
}
}
void Player::UpdateAllRatings()
{
for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
You can notice how i want to cap the new value outcome to 32000.
Before it gets calculated to percentages!
I tried using
if(newVal > 32000)
newVal = 32000;
Which would normally do the job i guess, but i'm stuck with an error
E0137 expression must be a modifiable lvalue
On the line newVal = 32000;
Remove const qualifier from newVal
float newVal = m_baseRatingValue[combatRating] * multiplier;
You declare newVal as a constant (float const newVal = ...), so you're not allowed to assign a new value.
Removing const should work for you, e.g.
float newVal = m_baseRatingValue[combatRating] * multiplier;
if (newVal > 32000)
newVal = 32000;
...

Replace largo if, else if... else with FOR or something more compact

I receive via POST a value. Then, I´m comparing the value received (1, 2, 3, 4, 5) with variables pre defined in my code.
Is it possible to do it with FOR or another way to simplify it without changing the functionality of the code?
Yes, I need to receive the value as number and compare it with variables (no MYSQL).
I set on each test the name, eg: $varname = "Paul";
Here´s what I´m doing and what I´d like to change.
Thanks a lot
// from previous page with input name thenumber
$thenumber = $_POST['thenumber'];
$option1 = "1";
$option1 = "2";
$option1 = "3";
$option1 = "4";
$option1 = "5";
$option1 = "6";
...
...
More options
if($thename == $option1)
{
$varname = "Paul";
}
else if ($thename == $option2)
{
$varname = "Louie";
}
else if ($thename == $option3)
{
$varname = "Dimitri";
}
...
...
...
It would be much cleaner to do this with a switch.
I don't think using a for loop will be a good idea.
Be sure to put a break after each case ends.
The default case is when $thename is none of the numbers in the cases.
switch ($thename) {
case 1:
$varname = "paul";
break;
case 2:
$varname = "Louie";
break;
case 3:
$varname = "Dimitri";
break;
...
default:
$varname = "default_name";
break;
}