Why can't the switch statement be applied on strings?
The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.
In order to generate the code for a switch statement the compiler must understand what it means for two values to be equal. For items like ints and enums, this is a trivial bit comparison. But how should the compiler compare 2 string values? Case sensitive, insensitive, culture aware, etc ... Without a full awareness of a string this cannot be accurately answered.
Additionally, C/C++ switch statements are typically generated as branch tables. It's not nearly as easy to generate a branch table for a string style switch.
Is the answer given for Why switch statement cannot be applied on strings? still true, even with C++11/14?
Yes, it still holds.
As stated here, the condition can be:
any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type, or a declaration of a single non-array variable of such type with a brace-or-equals initializer.
I came across that question a couple of days ago, and I guess you can figure out an alternative solution for the if/else
chain from there.
It mostly depends on your actual problem if it's possible, anyway the basic idea is to use a map of callable objects from which to access using your objects (strings in this case) as a key. That map has to be filled somehow before to use it, of course.
Why can't I use switch statement on a String?
Switch statements with String
cases have been implemented in Java SE 7, at least 16 years after they were first requested. A clear reason for the delay was not provided, but it likely had to do with performance.
Implementation in JDK 7
The feature has now been implemented in javac
with a "de-sugaring" process; a clean, high-level syntax using String
constants in case
declarations is expanded at compile-time into more complex code following a pattern. The resulting code uses JVM instructions that have always existed.
A switch
with String
cases is translated into two switches during compilation. The first maps each string to a unique integer—its position in the original switch. This is done by first switching on the hash code of the label. The corresponding case is an if
statement that tests string equality; if there are collisions on the hash, the test is a cascading if-else-if
. The second switch mirrors that in the original source code, but substitutes the case labels with their corresponding positions. This two-step process makes it easy to preserve the flow control of the original switch.
Switches in the JVM
For more technical depth on switch
, you can refer to the JVM Specification, where the compilation of switch statements is described. In a nutshell, there are two different JVM instructions that can be used for a switch, depending on the sparsity of the constants used by the cases. Both depend on using integer constants for each case to execute efficiently.
If the constants are dense, they are used as an index (after subtracting the lowest value) into a table of instruction pointers—the tableswitch
instruction.
If the constants are sparse, a binary search for the correct case is performed—the lookupswitch
instruction.
In de-sugaring a switch
on String
objects, both instructions are likely to be used. The lookupswitch
is suitable for the first switch on hash codes to find the original position of the case. The resulting ordinal is a natural fit for a tableswitch
.
Both instructions require the integer constants assigned to each case to be sorted at compile time. At runtime, while the O(1)
performance of tableswitch
generally appears better than the O(log(n))
performance of lookupswitch
, it requires some analysis to determine whether the table is dense enough to justify the space–time tradeoff. Bill Venners wrote a great article that covers this in more detail, along with an under-the-hood look at other Java flow control instructions.
Before JDK 7
Prior to JDK 7, enum
could approximate a String
-based switch. This uses the static valueOf
method generated by the compiler on every enum
type. For example:
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}
Swift Switch statement fails to match strings: What could cause this?
I suspect the problem is actually in your getWatchModel
method, specifically in the line:
var machine = CChar()
This allocates a single byte. You need to allocate size
bytes.
Here's one way of doing it:
func getWatchModel() -> String? {
var size: size_t = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: size)
sysctlbyname("hw.machine", &machine, &size, nil, 0)
return String(cString: machine, encoding: .utf8)
}
I suspect this lead to the String
containing garbage. I'm actually surprised you did not see any crashes.
can we use switch-case statement with strings in c? [duplicate]
No, you can't. Switch is intended to compare numeric types, and for extension char types.
Instead you should use the strcmp function, included in string header:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc != 4) {
puts("Incorrect usage");
return 1;
}
/* You should check the number of arguments */
char * op = argv[1];
int a = atoi(argv[2]);
int b = atoi(argv[3]);
/* You should check correct input too */
if (strcmp(op, "+") == 0)
printf("%d + %d = %d\n", a, b, a + b);
else if (strcmp(op, "-") == 0)
printf("%d - %d = %d\n", a, b, a - b);
/* Add more functions here */
return 0;
}
Why final variables cannot be used in switch statements?
There's nothing constant about an array. Its contents may be mutated at any time. The reference will say the same, but match[0]
could be something different at any point in time.
You have to use a constant value; one that's guaranteed not to change. Things like enums, primitive literals (and their boxed counterparts), and String
literals are guaranteed not to change through this process, and are valid for use.
This does mean, however, that you can use a variable which is marked final
and isn't mutable, though. Since array types are mutable, it doesn't work out as well - even if you reassign it to a final
variable. You have to declare the literal.
Here's a simple snippet below, revising your existing code:
String switchVar = "a";
final String matchZero = "a";
switch (switchVar) {
case matchZero: // valid since there's no way matchZero can ever be mutated
System.out.println("Matches");
break;
default:
System.out.println("No Match");
break;
}
Related Topics
Are Std::Vector Elements Guaranteed to Be Contiguous
What Does T&& (Double Ampersand) Mean in C++11
Usr/Bin/Ld: Cannot Find -L≪Nameofthelibrary≫
What Is a "Span" and When Should I Use One
Why C++11 In-Class Initializer Cannot Use Parentheses
When Should I Use the New Keyword in C++
Which Kind of Pointer Do I Use When
Using Generic Std::Function Objects With Member Functions in One Class
Avx2 What Is the Most Efficient Way to Pack Left Based on a Mask
Why Should I Not Include Cpp Files and Instead Use a Header
Difference Between Float and Double
Operator Overloading: Member Function Vs. Non-Member Function
Unresolved External Symbol on Static Class Members
How to Align Text to the Right Using Cout
Writing a Sequence of Numbers Like: 1 22 333 4444 55555
Why Do Function Pointer Definitions Work With Any Number of Ampersands '&' or Asterisks '*'