C中的类型"char"是什么意思?

What is the meaning of the type "char" in C?

以下引用自 C99 6.2.6.1

  1. Values stored in non-bit-field objects of any other object type consist of n × CHAR_BIT bits, where n is the size of an object of that type, in bytes. The value may be copied into an object of type unsigned char [ n ] (e.g., by memcpy); the resulting set of bytes is called the object representation of the value.

Q1。 6.2.6.1 p5 是否意味着仅当对象除以 char 时才定义对象表示?(为什么要除以 char,而不是保留其本身?)

// illustrating for Q1
#include <string.h>

int main(void)
{
  int var = 5; // var is not the object representation of itself
  char arr[sizeof(int)];
  memcpy(arr, &var, sizeof(int)); // arr is the object representation of var
}
  1. Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. If such a representation is produced by a side effect that modifies all or any part of the object by an lvalue expression that does not have character type, the behavior is undefined. Such a representation is called a trap representation.

Q2。为什么存储陷阱表示值时不仅字符类型会导致未定义的行为?(为什么读取陷阱表示未定义的行为除非对象没有字符类型?)

Q3.我想通常我们不必阅读陷阱表示。但是,如果有人尝试阅读它,6.2.6.1 p6 是否意味着应该将任何更宽的类型(比 char)复制到 char 数组中作为 Q1 代码示例?

// illustrating for Q3
#include <stdio.h>
#include <string.h>
#define TRAPVAL 0x12345678 // assume 0x12345678 is trap representation to the type int

int main(void)
{
  int var = TRAPVAL;
  printf("var: %x\n", var); // undefined behavior

  char arr[sizeof(int)];
  memcpy(arr, &var, sizeof(int));

  printf("var: ");
  for (int i = 0; i < sizeof(int); i++) 
    printf("%hhx ", arr[i]); // well defined
}

Q1. Does 6.2.6.1 p5 mean object representation is defined only when an objected is divided by char?

没有。它只是意味着对象表示是 unsigned char.

类型值的序列

(why should it be divided by char, rather than remaining itself?)

char(和unsigned char)的大小是测量对象大小的单位。 unsigned char 没有填充位,因此它的所有位对其值都很重要。因此 unsigned char 类型的值是 C 内存模型中的基本存储单位。

另请注意,有一些方法可以访问对象表示的各个字节,而无需将表示复制到数组,但语言规范选择此定义以避免形成一组循环定义。

Q2. Why doesn't only character type cause undefined behavior when trap representation value is stored?(why is to read trap representation undefined behavior unless an object doesn't have character type?)

陷阱表示是将字节序列解释为特定类型的值的特征。我怀疑你缺少的是 C 没有为你如何阅读给定对象的表示提供很多选择:粗略地说,你可以将它作为兼容类型的对象或作为 [signed 的序列|unsigned] char.* 只有后一种选择不会尝试将所讨论的表示解释为类型的对象,该类型是陷阱表示.

Q3. I guess generally we don't have to read trap representation. But if one try to read it, does 6.2.6.1 p6 mean any wider type(than char) should be copied in a char array as Q1 code example?

没有。您可以通过获取对象的地址、将其转换为类型 unsigned char * 并通过指针读取字节来检查对象表示的字节:

my_type o;
/* ... assign a value to o ... */
unsigned char *p = &o;

for (size_t i = 0; i < sizeof o; i++) {
    printf("%hhx", *p++);
}

但是,请注意,如果 objective 要在 o 中生成陷阱表示,则“为 o 赋值”部分会很棘手。


*您还可以将对象的表示作为包含该对象作为成员的聚合或联合的表示的一部分来读取,但这不是规范所讨论的内容关于这里。