什么时候可以用char *等式来比较C字符串?

时间:2022-07-15 22:28:23

I know it doesn't make sense for two arbitrary c-strings (const char *) by comparing them (a == b).

我知道对任意两个c-string (const char *)进行比较(a = b)是没有意义的。

But I think that when both are defined by the SAME string literal, this is legal.

但是我认为当两个字符串都由相同的字符串文字定义时,这是合法的。

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?).

如果这段代码在头文件中,这没有什么区别,是吗?(我认为标准要求每餐在每个编译单元中都有相同的值?)

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. 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.

我从初学者那里发现了很多问题,问他们是否应该使用strcmp,但我找不到一个能回答这个特殊情况的例子。如果您能给我指出C标准的正确部分,以便我能真正理解其中的微妙之处,我将非常感激您的帮助。

2 个解决方案

#1


3  

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:

下列任何一项应成立:

  • 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], e.g. 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. This differs from:

s1和s2的值不能保证是相同的,因为这两个字符串常量可以彼此不同,尽管编译器可能会选择使它们相同。这不同于:

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

Where s1 and s2 will be the same, and this mirrors your case.

s1和s2是一样的,这反映了你的情况。

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. But the pointers to strings constants are effectively just that.

正如您所提到的,hour_to_meal_map包含数值常量(最好是enum的成员),以及随后映射到字符串数组的常量,更有意义。但是指向字符串常量的指针实际上就是这样。

#2


0  

I can think of a few cases where char * equality is meaningful:

我能想到几个例子,其中char * equality是有意义的:

  1. the case you gave: by copying from the same pointer
  2. 你给出的例子是:从同一个指针复制
  3. 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.
  4. 对于大多数(所有?)编译器:使用同一翻译单元中的任何同值字符串。这是一种非常常见的优化,并且可以很容易地进行测试。
  5. if you explicitly pass the string through an intern() function
  6. 如果显式地将字符串传递给一个intern()函数
  7. as a quick short-circuit comparison before performing an expensive check of the value
  8. 作为一个快速的短路比较,在执行一个昂贵的价值检查之前

#1


3  

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:

下列任何一项应成立:

  • 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], e.g. 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. This differs from:

s1和s2的值不能保证是相同的,因为这两个字符串常量可以彼此不同,尽管编译器可能会选择使它们相同。这不同于:

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

Where s1 and s2 will be the same, and this mirrors your case.

s1和s2是一样的,这反映了你的情况。

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. But the pointers to strings constants are effectively just that.

正如您所提到的,hour_to_meal_map包含数值常量(最好是enum的成员),以及随后映射到字符串数组的常量,更有意义。但是指向字符串常量的指针实际上就是这样。

#2


0  

I can think of a few cases where char * equality is meaningful:

我能想到几个例子,其中char * equality是有意义的:

  1. the case you gave: by copying from the same pointer
  2. 你给出的例子是:从同一个指针复制
  3. 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.
  4. 对于大多数(所有?)编译器:使用同一翻译单元中的任何同值字符串。这是一种非常常见的优化,并且可以很容易地进行测试。
  5. if you explicitly pass the string through an intern() function
  6. 如果显式地将字符串传递给一个intern()函数
  7. as a quick short-circuit comparison before performing an expensive check of the value
  8. 作为一个快速的短路比较,在执行一个昂贵的价值检查之前