I am comparing these two strings: "code" and "test"
When I type this in Visual Studio:
cout<<("t"<"c")<<endl;
cout<<("c"<"t")<<endl;
cout<<("code"<"test")<<endl;
cout<<("test"<"cose")<<endl;
The result is:
1
0
1
1
Which does not make sense, when I tried to try it on ideone.com, the result becomes:
0
1
1
1
What is going wrong here?
You're comparing pointer values, not strings (note: "cose" is a different literal than "code", ¹guaranteed giving a different pointer).
Use std::string from the <string> header to get meaningful string operations.
Then you can also use literals like "code"s.
#include <iostream>
#include <string>
using namespace std;
auto main() -> int
{
cout << boolalpha;
cout << ("t"s < "c"s) << endl;
cout << ("c"s < "t"s) << endl;
cout << ("code"s < "test"s) << endl;
cout << ("test"s < "cose"s) << endl;
}
Formally the code in the question,
cout<<("t"<"c")<<endl;
cout<<("c"<"t")<<endl;
cout<<("code"<"test")<<endl;
cout<<("test"<"cose")<<endl;
… has implementation defined behavior, because
C++11 §5.9/2 2nd dash (expr.rel):
” If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified.
You can however compare such pointers in a well-defined way via std::less and family, because
C++11 20.8.5/8 (comparisons):
” For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.
But on the third and gripping hand, while the pointer comparisons can be useful in some situations, you probably wanted to compare the string literals. The standard library offers e.g. strcmp in order to do that. But preferably use std::string, as noted at the start.
The literal "code" denotes an immutable null-terminated string of char values. With the final null-byte it's a total of five char values. Hence the type is char const[5].
As an expression used in a context where a pointer is expected, the expression denoting this array (namely, the "code" literal) decays to a pointer to the first item, a char const* pointer.
This is the usual decay of array expression to pointer, but in C++03 and earlier there was also a special rule for literals that allowed a decay to just char* (no const).
Notes:
¹ Two identical string literals can give different pointers, or the same pointer, depending on the compiler and options used.
String literals, like e.g. "t" are actually constant arrays of characters (including terminator).
When you use a string literal then what you get is a pointer to its first character.
So when you do "t" < "c" you are comparing two unrelated pointers. If "t" < "c" is true or not depends on where the compiler have decided to put the string literal arrays.
If you want to compare strings, you either should use std::string, or the old C-function strcmp.
Related
I have a single char value, and I need to cast/convert it to a std::string. How can I do this?
I know how to go the opposite way, to retrieve a char from a std::string object: you just need to index the string at the appropriate location. For example: str[0] will retrieve the first character in the string.
But how do I go the other way? I want something like:
char c = 34;
std::string s(c);
…but this doesn't work (the string is always empty).
You can use any/all of the following to create a std::string from a single character:
std::string s(1, c);
std::cout << s << std::endl;
std::string s{c};
std::cout << s << std::endl;
std::string s;
s.push_back(c);
std::cout << s << std::endl;
std::string has a constructor that takes a number and a character. The character will repeat for the given number of times. Thus, you should use:
std::string str(1, ch);
You can try stringstream. An example is below:
#include <sstream>
#include <string>
std::stringstream ss;
std::string target;
char mychar = 'a';
ss << mychar;
ss >> target;
This solution will work regardless of the number of char variables you have:
char c1 = 'z';
char c2 = 'w';
std::string s1{c1};
std::string s12{c1, c2};
You still can use the string constructor taking two iterators:
char c = 'x';
std::string(&c, &c + 1);
Update:
Good question James and GMan. Just searched freely downloadable "The New C Standard" by Derek M. Jones for "pointer past" and my first hit was:
If the expression P points to an
element of an array object and the
expression Q points to the last
element of the same array object, the
pointer expression Q+1 compares
greater than P... even though Q+1 does
not point to an element of the array
object...
On segmented architectures
incrementing a pointer past the end of
a segment causes the address to wrap
segmented architecture around to the
beginning of that segment (usually
address zero). If an array is
allocated within such a segment,
either the implementation must ensure
that there is room after the array for
there to be a one past the end
address, or it uses some other
implementation technique to handle
this case (e.g., if the segment used
is part of a pointer’s representation,
a special one past the end segment
value might be assigned)...
The C relational operator model enables
pointers to objects to be treated in
the same way as indexes into array
objects. Relational comparisons
between indexes into two different
array objects (that are not both
subobjects of a larger object) rarely
have any meaning and the standard does
not define such support for pointers.
Some applications do need to make use
of information on the relative
locations of different objects in
storage. However, this usage was not
considered to be of sufficient general
utility for the Committee to specify a
model defining the behavior...
Most implementations perform no checks
prior to any operation on values
having pointer type. Most processors
use the same instructions for
performing relational comparisons
involving pointer types as they use
for arithmetic types. For processors
that use a segmented memory
architecture, a pointer value is often
represented using two components, a
segment number and an offset within
that segment. A consequence of this
representation is that there are many
benefits in allocating storage for
objects such that it fits within a
single segment (i.e., storage for an
object does not span a segment
boundary). One benefit is an
optimization involving the generated
machine code for some of the
relational operators, which only needs
to check the segment offset component.
This can lead to the situation where
p >= q is false but p > q is true,
when p and q point to different objects.
This works on gcc C++ 4.9.2 (http://ideone.com/f3qhTe)
#include <iostream>
using namespace std;
int main() {
// your code goes here
std::string test;
test = (char) 76;
test += (char) 77;
test += (char) 78;
test += (char) 79;
std::cout << "test contains: " << test << std::endl;
return 0;
}
In most cases you can just use {ch}.
std::string s = {ch}; // works
infix.push({ch}); // works
This utilises the std::initializer_list constructor of std::string.
I don't know Java that much, but the closest in C++ to your ch + "" is probably std::string{} + ch. Note, that "" is not a std::string, and you cannot overload operators for fundamental types, hence ch+"" cannot possibly result in a std::string.
However, std::string{} + ch involves 2 strings. I suppose the temporary can be optimized away by the compiler, though to construct a string from one character this is perfectly fine: std::string(1,ch).
For other constructors of std::string I refer you to https://en.cppreference.com/w/cpp/string/basic_string/basic_string.
You can set a string equal to a char.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
char one = '1';
char two = '2';
s = one;
s += two;
cout << s << endl;
}
./test
12
I have a single char value, and I need to cast/convert it to a std::string. How can I do this?
I know how to go the opposite way, to retrieve a char from a std::string object: you just need to index the string at the appropriate location. For example: str[0] will retrieve the first character in the string.
But how do I go the other way? I want something like:
char c = 34;
std::string s(c);
…but this doesn't work (the string is always empty).
You can use any/all of the following to create a std::string from a single character:
std::string s(1, c);
std::cout << s << std::endl;
std::string s{c};
std::cout << s << std::endl;
std::string s;
s.push_back(c);
std::cout << s << std::endl;
std::string has a constructor that takes a number and a character. The character will repeat for the given number of times. Thus, you should use:
std::string str(1, ch);
You can try stringstream. An example is below:
#include <sstream>
#include <string>
std::stringstream ss;
std::string target;
char mychar = 'a';
ss << mychar;
ss >> target;
This solution will work regardless of the number of char variables you have:
char c1 = 'z';
char c2 = 'w';
std::string s1{c1};
std::string s12{c1, c2};
You still can use the string constructor taking two iterators:
char c = 'x';
std::string(&c, &c + 1);
Update:
Good question James and GMan. Just searched freely downloadable "The New C Standard" by Derek M. Jones for "pointer past" and my first hit was:
If the expression P points to an
element of an array object and the
expression Q points to the last
element of the same array object, the
pointer expression Q+1 compares
greater than P... even though Q+1 does
not point to an element of the array
object...
On segmented architectures
incrementing a pointer past the end of
a segment causes the address to wrap
segmented architecture around to the
beginning of that segment (usually
address zero). If an array is
allocated within such a segment,
either the implementation must ensure
that there is room after the array for
there to be a one past the end
address, or it uses some other
implementation technique to handle
this case (e.g., if the segment used
is part of a pointer’s representation,
a special one past the end segment
value might be assigned)...
The C relational operator model enables
pointers to objects to be treated in
the same way as indexes into array
objects. Relational comparisons
between indexes into two different
array objects (that are not both
subobjects of a larger object) rarely
have any meaning and the standard does
not define such support for pointers.
Some applications do need to make use
of information on the relative
locations of different objects in
storage. However, this usage was not
considered to be of sufficient general
utility for the Committee to specify a
model defining the behavior...
Most implementations perform no checks
prior to any operation on values
having pointer type. Most processors
use the same instructions for
performing relational comparisons
involving pointer types as they use
for arithmetic types. For processors
that use a segmented memory
architecture, a pointer value is often
represented using two components, a
segment number and an offset within
that segment. A consequence of this
representation is that there are many
benefits in allocating storage for
objects such that it fits within a
single segment (i.e., storage for an
object does not span a segment
boundary). One benefit is an
optimization involving the generated
machine code for some of the
relational operators, which only needs
to check the segment offset component.
This can lead to the situation where
p >= q is false but p > q is true,
when p and q point to different objects.
This works on gcc C++ 4.9.2 (http://ideone.com/f3qhTe)
#include <iostream>
using namespace std;
int main() {
// your code goes here
std::string test;
test = (char) 76;
test += (char) 77;
test += (char) 78;
test += (char) 79;
std::cout << "test contains: " << test << std::endl;
return 0;
}
In most cases you can just use {ch}.
std::string s = {ch}; // works
infix.push({ch}); // works
This utilises the std::initializer_list constructor of std::string.
I don't know Java that much, but the closest in C++ to your ch + "" is probably std::string{} + ch. Note, that "" is not a std::string, and you cannot overload operators for fundamental types, hence ch+"" cannot possibly result in a std::string.
However, std::string{} + ch involves 2 strings. I suppose the temporary can be optimized away by the compiler, though to construct a string from one character this is perfectly fine: std::string(1,ch).
For other constructors of std::string I refer you to https://en.cppreference.com/w/cpp/string/basic_string/basic_string.
You can set a string equal to a char.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
char one = '1';
char two = '2';
s = one;
s += two;
cout << s << endl;
}
./test
12
This question already has an answer here:
Comparing uint8_t data with string
(1 answer)
Closed 4 years ago.
I'm new to C and C++, and can't seem to work out how I need to compare these values:
Variable I'm being passed:
typedef struct {
uint8_t ssid[33];
String I want to match. I've tried both of these:
uint8_t AP_Match = "MatchString";
unsigned char* AP_Match = "MatchString";
How I've attempted to match:
if (strncmp(list[i].ssid, "MatchString")) {
if (list[i].ssid == AP_Match) {
if (list[i].ssid == "MatchString") {
// This one fails because String is undeclared, despite having
// an include line for string.h
if (String(reinterpret_cast<const char*>(conf.sta.ssid)) == 'MatchString') {
I've noodled around with this a few different ways, and done some searching. I know one or both of these may be the wrong type, but I'm not sure to get from where I am to working.
There is no such type as "String" defined by any C standard. A string is just an array of characters that are stored as unsigned values based on the chosen encoding. 'string.h' provides various functions for comparison, concatenation, etc. but it can only work if the values you are passing to it are coherent.
The operator "==" is also undefined for string comparisons, because it would require comparing each character at each index, for two arrays that may not be the same size and ultimately may use different encodings, despite the same underlying unsigned integer representation (raising the prospect of false positive comparisons). You can possibly define your own function to do it (note C doesn't allow overloading operators), but otherwise you're stuck with what the standard libraries provide.
Note that strncmp() takes a size parameter for the number of characters to compare (your code is missing this). https://www.tutorialspoint.com/c_standard_library/c_function_strncmp.htm
Otherwise you would be looking at the function strcmp(), which requires the input strings to be null-terminated (last character equal to '\0'). Ultimately it's up to you to consider what the possible combinations of inputs could be and how they are stored and to use a comparison function that is robust to all possibilities.
As a final side note
if (list[i].ssid == "MatchString") {
Since ssid is an array, you should know that when you do this comparison, you are not actually accessing the contents of ssid, but rather the address of the first element of ssid. When you pass list[i].ssid into strcmp (or strncmp), you are passing a pointer to the first element of the array in memory. The function then iterates over the entire array until it reaches the null character (in the case of strcmp) or until it has compared the specified number of elements (in the case of strncmp).
To match two strings use strcmp:
if (0==strcmp(str1, str2))
str1 and str2 are addresses to memory holding a null terminated string. Return value zero means the strings are equal.
In your case one of:
if (0==strcmp(list[i].ssid, AP_Match))
if (0==strcmp(list[i].ssid, "MatchString"))
I have a single char value, and I need to cast/convert it to a std::string. How can I do this?
I know how to go the opposite way, to retrieve a char from a std::string object: you just need to index the string at the appropriate location. For example: str[0] will retrieve the first character in the string.
But how do I go the other way? I want something like:
char c = 34;
std::string s(c);
…but this doesn't work (the string is always empty).
You can use any/all of the following to create a std::string from a single character:
std::string s(1, c);
std::cout << s << std::endl;
std::string s{c};
std::cout << s << std::endl;
std::string s;
s.push_back(c);
std::cout << s << std::endl;
std::string has a constructor that takes a number and a character. The character will repeat for the given number of times. Thus, you should use:
std::string str(1, ch);
You can try stringstream. An example is below:
#include <sstream>
#include <string>
std::stringstream ss;
std::string target;
char mychar = 'a';
ss << mychar;
ss >> target;
This solution will work regardless of the number of char variables you have:
char c1 = 'z';
char c2 = 'w';
std::string s1{c1};
std::string s12{c1, c2};
You still can use the string constructor taking two iterators:
char c = 'x';
std::string(&c, &c + 1);
Update:
Good question James and GMan. Just searched freely downloadable "The New C Standard" by Derek M. Jones for "pointer past" and my first hit was:
If the expression P points to an
element of an array object and the
expression Q points to the last
element of the same array object, the
pointer expression Q+1 compares
greater than P... even though Q+1 does
not point to an element of the array
object...
On segmented architectures
incrementing a pointer past the end of
a segment causes the address to wrap
segmented architecture around to the
beginning of that segment (usually
address zero). If an array is
allocated within such a segment,
either the implementation must ensure
that there is room after the array for
there to be a one past the end
address, or it uses some other
implementation technique to handle
this case (e.g., if the segment used
is part of a pointer’s representation,
a special one past the end segment
value might be assigned)...
The C relational operator model enables
pointers to objects to be treated in
the same way as indexes into array
objects. Relational comparisons
between indexes into two different
array objects (that are not both
subobjects of a larger object) rarely
have any meaning and the standard does
not define such support for pointers.
Some applications do need to make use
of information on the relative
locations of different objects in
storage. However, this usage was not
considered to be of sufficient general
utility for the Committee to specify a
model defining the behavior...
Most implementations perform no checks
prior to any operation on values
having pointer type. Most processors
use the same instructions for
performing relational comparisons
involving pointer types as they use
for arithmetic types. For processors
that use a segmented memory
architecture, a pointer value is often
represented using two components, a
segment number and an offset within
that segment. A consequence of this
representation is that there are many
benefits in allocating storage for
objects such that it fits within a
single segment (i.e., storage for an
object does not span a segment
boundary). One benefit is an
optimization involving the generated
machine code for some of the
relational operators, which only needs
to check the segment offset component.
This can lead to the situation where
p >= q is false but p > q is true,
when p and q point to different objects.
This works on gcc C++ 4.9.2 (http://ideone.com/f3qhTe)
#include <iostream>
using namespace std;
int main() {
// your code goes here
std::string test;
test = (char) 76;
test += (char) 77;
test += (char) 78;
test += (char) 79;
std::cout << "test contains: " << test << std::endl;
return 0;
}
In most cases you can just use {ch}.
std::string s = {ch}; // works
infix.push({ch}); // works
This utilises the std::initializer_list constructor of std::string.
I don't know Java that much, but the closest in C++ to your ch + "" is probably std::string{} + ch. Note, that "" is not a std::string, and you cannot overload operators for fundamental types, hence ch+"" cannot possibly result in a std::string.
However, std::string{} + ch involves 2 strings. I suppose the temporary can be optimized away by the compiler, though to construct a string from one character this is perfectly fine: std::string(1,ch).
For other constructors of std::string I refer you to https://en.cppreference.com/w/cpp/string/basic_string/basic_string.
You can set a string equal to a char.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
char one = '1';
char two = '2';
s = one;
s += two;
cout << s << endl;
}
./test
12
When comparing a string literal with another string literal with the == operator (or !=), is the result well defined?
For example, are the following guaranteed to hold?
assert("a" == "a");
assert("a" != "b");
Please don't say stuff like "use std::string" instead. I just want to know this specific case.
"a" == "a"
This expression may yield true or false; there are no guarantees. The two "a" string literals may occupy the same storage or they may exist at two different locations in memory.
I think that the closest language in the C++ Standard is: "Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation defined" (C++11 §2.14.5/12). There are no other requirements or restrictions, so the result is left unspecified.
"a" != "b"
This expression must yield false because there is no way that these two string literals can occupy the same location in memory: "a"[0] != "b"[0].
When you compare string literals in this way, you are really comparing the pointers to the initial elements in the arrays.
Because we are comparing pointers, the relational comparisons (<, >, <=, and >=) are even more problematic than the equality comparisons (== and !=) because only a restricted set of pointer comparisons may be performed using the relational comparisons. Two pointers may only be relationally compared if they are both pointers into the same array or pointers into the same object.
If the two "a" string literals occupy the same location in memory, then "a" < "a" would be well-defined and would yield false, because both pointers point to the initial element ('a') of the same array.
However, if the two "a" string literals occupy different locations in memory, the result of "a" < "a" is undefined, because the two pointers being compared point into entirely unrelated objects.
Because "a" and "b" can never occupy the same location in memory, "a" < "b" always has undefined behavior. The same is true for the other relational comparison operators.
If you did, for some reason, want to relationally compare two string literals and have well-defined results, you can use the std::less comparer, which provides a strict-weak ordering over all pointers. There are also std::greater, std::greater_equal, and std::less_equal comparers. Given that string literals with the same contents may not compare equal, I don't know why one would ever want to do this, but you can.
The idea is that in C++ string literals are arrays. Since arrays do not have comparison operators defined for them, they are compared using the next best fit - the pointer comparison operator, as arrays will implicitly decay to pointers, so any comparison compares address and not content. Since "a" and "b" cannot be at the same memory location, "a" != "b" is a true assertion. It also forms a valid static assertion. No such guarantee can be made about "a" == "a", though GCC with -fmerge-constants (implied at -O1) can make a reasonably strong probability and -fmerge-all-constants can give you a guarantee (that potentially results in non-conforming behavior).
If you happen to want a content-based comparison, you can always use assert(!strcmp("a", "a")). Or, you can use some sort of constexpr based strcmp for a static assertion:
constexpr bool static_strequal_helper(const char * a, const char * b, unsigned len) {
return (len == 0) ? true : ((*a == *b) ? static_strequal_helper(a + 1, b + 1, len - 1) : false);
}
template <unsigned N1, unsigned N2>
constexpr bool static_strequal(const char (&str1)[N1], const char (&str2)[N2]) {
return (N1 == N2) ? static_strequal_helper(&(str1[0]), &(str2[0]), N1) : false;
}
static_assert(static_strequal("asdf", "asdf"), "no error - strings are equal");
static_assert(static_strequal("asdf", "jkl;"), "strings are not equal");
assert(!strcmp("asdf", "jkl;")); //no compile error - runtime error
//cannot use strcmp in static assert as strcmp is not constexpr...
Then, compile with g++ -std=c++0x (or -std=c++11 for gcc >= 4.7), and...
error: static assertion failed: "strings are not equal"