简体   繁体   English

什么时候可以通过char *相等来比较C字符串?

[英]When is it okay to compare C strings by char * equality?

I know it doesn't make sense for two arbitrary c-strings ( const char * ) by comparing them (a == b) . 我知道通过比较两个任意c字符串( const char * )是没有意义的(a == b)

But I think that when both are defined by the SAME string literal, this is legal. 但我认为,当两者都由SAME字符串文字定义时,这是合法的。

For example, here: 例如,这里:

#include <stddef.h>

const char * const meals[] = {
    "none",
    "breakfast",
    "lunch",
    "dinner"
};

#define NO_MEALS  meals[0]
#define BREAKFAST meals[1]
#define LUNCH     meals[2]
#define DINNER    meals[3]

// i hours after midnight, hour_to_meals_map[floor(i)] is being served.
const char * hour_to_meal_map[] = {
    NO_MEALS,
    NO_MEALS,
    NO_MEALS,
    NO_MEALS,
    NO_MEALS,
    BREAKFAST, // i = 5
    BREAKFAST,
    BREAKFAST,
    BREAKFAST,
    BREAKFAST,
    BREAKFAST,
    LUNCH, // i = 11
    LUNCH,
    LUNCH,
    LUNCH,
    LUNCH,
    LUNCH,
    DINNER, // i = 17
    DINNER,
    DINNER,
    DINNER,
    DINNER,
    DINNER,
    DINNER // i = 23
};

// Returns a boolean for whether the two hours have the same meal being eaten.
int same_meal(size_t hour_one, size_t hour_two) {
    return hour_to_meal_map[hour_one] == hour_to_meal_map[hour_two];
}

(As for why you would make hour_to_meal_map map to strings rather than to indices is anyone's guess.. but I'm working on a project that is set up this way.) (至于为什么你会将hour_to_meal_map映射到字符串而不是索引是任何人的猜测..但我正在研究以这种方式设置的项目。)

Am I correct that this is legal here, and that what matters is that there is only one spot that each value is written as a literal? 我是否认为这在这里是合法的,重要的是每个值只有一个字母写成文字? ( #define NO_MEALS "none" was deliberately avoided!!) #define NO_MEALS "none"故意避免!)

If this code is in a header file, that doesn't make a difference, does it? 如果这个代码在头文件中,这没有什么区别,是吗? (I expect the standard requires that meals have identical values in each compilation unit?). (我希望标准要求每个编辑单元中的meals具有相同的值?)。

I find lots of questions from beginners asking about cases where it's pretty clear they should be using strcmp , but I can't find one that answers this particular case. 我发现许多初学者的问题都在询问他们应该使用strcmp ,但是我找不到能够解决这个问题的案例。 Any help would be appreciated, particularly if you can point me to the right part of the C standard so I can be really sure I understand all the subtleties. 任何帮助,将不胜感激,特别是如果你能指点C标准的右侧部分,所以我可以确定我了解所有的细微之处。

Comparing two strings of the same type with == or != is always legal. 将两个相同类型的字符串与==!=比较总是合法的。 This is detailed in section 6.5.9 of the C standard which details Equality Operators: 详见C标准第6.5.9节,详细说明了平等操作员:

2 One of the following shall hold: 2下列之一应持有:

  • both operands have arithmetic type; 两个操作数都有算术类型;
  • both operands are pointers to qualified or unqualified versions of compatible types; 两个操作数都是指向兼容类型的限定或非限定版本的指针;
  • one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void ;or 一个操作数是指向对象类型的指针,另一个是指向void的限定或非限定版本的指针;或者
  • one operand is a pointer and the other is a null pointer constant. 一个操作数是一个指针,另一个是空指针常量。

... ...

4 Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function , both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space 4 两个指针比较相等,当且仅当两个都是空指针时, 两者都是指向同一对象的指针(包括指向对象的指针和开头的子对象)或函数 ,两者都是指向同一对象的最后一个元素的指针数组对象,或者一个是指向一个数组对象末尾的指针,另一个是指向不同数组对象的开头的指针,该数组对象恰好跟随地址空间中的第一个数组对象

In this case you have an array of pointers, and you assign the value of one of those pointers into another array. 在这种情况下,您有一个指针数组,并将其中一个指针的值分配给另一个数组。 So if you compare two pointers and they both contain the value of (for example) meals[0] , eg the address of the string constant "none", they are guaranteed to compare equal. 因此,如果您比较两个指针并且它们都包含(例如) meals[0] ,例如字符串常量“none”的地址,则它们保证比较相等。

What you have to watch out for is if a given string constant is used in multiple places. 您需要注意的是,如果在多个位置使用给定的字符串常量。 In that case, they're not necessarily the same. 在那种情况下,它们不一定相同。

For example, given this: 例如,鉴于此:

const char *s1 = "test";
const char *s2 = "test";

The values of s1 and s2 are not guaranteed to be the same as the two strings constants can be distinct from each other, although compilers may choose to make them the same. s1s2的值不保证是相同的,因为两个字符串常量可以彼此不同,尽管编译器可以选择使它们相同。 This differs from: 这不同于:

const char *s1 = "test";
const char *s2 = s1;

Where s1 and s2 will be the same, and this mirrors your case. 其中s1s2 是相同的,这反映了你的情况。

As you mentioned, it would make more sense for hour_to_meal_map to contain numeric constants (preferably members of an enum ) and for those constants to subsequently map to an array of strings. 正如您所提到的,对于hour_to_meal_map ,包含数字常量(最好是enum成员)以及随后映射到字符串数组的常量会更有意义。 But the pointers to strings constants are effectively just that. 但是指向字符串常量的指针实际上就是这样。

I can think of a few cases where char * equality is meaningful: 我可以想到char *等式有意义的几种情况:

  1. the case you gave: by copying from the same pointer 你给的情况:从同一个指针复制
  2. for most (all?) compilers: with any same-value string literals in the same translation unit. 对于大多数(所有?)编译器:在同一个翻译单元中使用任何相同值的字符串文字。 This is an extremely common optimization, and can easily be tested anyway. 这是一种非常常见的优化,无论如何都可以轻松进行测试。
  3. if you explicitly pass the string through an intern() function 如果你通过intern()函数显式传递字符串
  4. as a quick short-circuit comparison before performing an expensive check of the value 在进行昂贵的价值检查之前,作为快速短路比较

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM