【问题标题】:Why does sizeof(*"327") return 1 instead of 8 on a 64 bit system?为什么 sizeof(*"327") 在 64 位系统上返回 1 而不是 8?
【发布时间】:2018-03-24 03:14:14
【问题描述】:
 printf("%lu \n", sizeof(*"327"));

我一直认为在 64 位系统上指针的大小是 8 字节,但是这个调用一直返回 1。有人可以解释一下吗?

【问题讨论】:

  • sizeof(*"327")sizeof(char) 因为 * 取消引用您的文字字符串的第一个字符。试试sizeof(char *)
  • 我还建议您阅读例如this printf (and family) reference,因为 "%lu"sizeof 参数的错误格式。
  • 旁注:sizeof 不是可以调用的函数。
  • 你可能一直在想sizeof(&"327")

标签: c sizeof


【解决方案1】:

* 放在字符串文字之前将取消对该文字的引用(因为字符串文字是字符数组,并且在此上下文中将衰减为指向其第一个元素的指针)。声明

printf("%zu \n", sizeof(*"327")); 

等价于

printf("%zu \n", sizeof("327"[0]));  

"327"[0] 将给出字符串文字"327" 的第一个元素,即字符'3'"327" 的类型,衰减后是 char *,在解除引用后,它会给出 char 类型的值,最终 sizeof(char)1

【讨论】:

  • @dwilliss;在 C 中,'3' 是一个整数常量。根据 C 标准,整数字符常量的类型为 int
  • @Wilson 你误会了。在 C 中,所有字符常量始终是 int 类型。只有在 C++ 中,'3'(或 'm')类型为 char。不相信? int main() { printf("%zu\n", sizeof 'm');}
  • 它并没有真正解除对'3' 的引用(即字符文字)。它将字符串文字 (char*) 取消引用到第一个元素,该元素将是 char,因此是单个字节 (*(char*) = (char))。恰好取消引用的字符串文字的值是(char)'3',因为这是字符串中的第一个字符。
  • @dwilliss sizeof('3') 一直与sizeof(int) 相同。同样,sizeof(*"3") 始终与sizeof(char) 相同。尽管听起来不合逻辑,但字符文字不是char 类型。事实上,C 中的 all 文字至少是 int 的大小。要获得char 类型的内容,您需要一个包含文字以外内容的表达式。
【解决方案2】:

声明:

printf("%lu \n", sizeof(*"327"));

实际上打印char 的大小,因为使用* 取消引用字符串327 的第一个字符。将其更改为:

char* str = "327";
printf("%zu \n", sizeof(str));

注意这里我们需要使用%zu,而不是%lu,因为we are printing a size_t value

【讨论】:

    【解决方案3】:

    字符串字面量是一个匿名的静态字符数组,它衰减为指向其第一个字符的指针——即char * 类型的指针值。

    因此,*"abc" 这样的表达式等价于*someArrayOfCharName,而*&firstCharInArray 又等价于firstCharInArray。而sizeof(firstCharInArray) 就是sizeof(char) 也就是1

    【讨论】:

    • 几乎正确。即使数组是只读的(不能修改),它也不是const。所以它衰减到一个普通的非常量char *。这是使 C 和 C++ 不同的原因之一。
    • 技术上它不会衰减,除非在衰减上下文中使用。这就是为什么sizeof "abcd" 是 5。应用解引用运算符当然是一个衰减上下文
    【解决方案4】:

    haccks 的好回答。

    此外,您的代码行为是未定义,因为您使用了错误的格式说明符。

    所以,请使用%zu 而不是%lu,因为sizeof() 返回size_tsize_tunsigned

    C11 标准:§7.21.6.1:第 9 段:

    如果转换规范无效,则行为是 undefined.225) 如果任何参数不是正确的类型 相应的转换规范,行为未定义。

    【讨论】:

    • 虽然这是真的,但这应该是一个评论。如果size_t 小于或等于unsigned long,则没有UB。
    • @Lundin 不管size_t 是什么类型,要么不升级,要么升级为signed int/unsigned int,所以只有这样你才能得到unsigned long传递给printf 是如果size_t 已经是unsigned long。那么,如果size_t 是其他任何东西,我不明白你怎么能说行为已定义。
    • @hvd 很好,但这不是现实世界的问题,也不能回答问题。在现实世界中,long 和 size_t 的大小相同,没有问题。或者 long 是 32 位,而 size_t 更大,在这种情况下,您可能最终会读取 size_t 的一部分,但不会调用任何 UB。
    • @Lundin “但你并没有调用任何 UB”——这个答案已经解释了你错的原因。该标准明确声明该行为未定义,并且 必须 未定义,因为没有明智的方法来定义适用于所有调用约定的行为。同意它没有回答问题,但它完全准确,值得发表评论。
    • 可能未定义; size_t 的常见实现选择是 unsigned long 的 typedef
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 2021-09-26
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多