gcc 内部使用相同的位表示 int 和 char 吗?

2024-05-05

我只是为了好玩而玩弄 unicode 字符(不使用 wchar_t 支持)。我只使用常规的 char 数据类型。我注意到,当以十六进制打印它们时,它们显示了完整的 4 个字节,而不是仅一个字节。

对于前。考虑这个 c 文件:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *s = (char *) malloc(100);
    fgets(s, 100, stdin);
    while (s && *s != '\0') {
            printf("%x\n", *s);
            s++;
    }
    return 0;
}

使用 gcc 编译并输入“cent”符号(十六进制:c2 a2)后,我得到以下输出

$ ./a.out
¢
ffffffc2: ?
ffffffa2: ?
a: 

因此,我不是只打印 c2 和 a2,而是得到了整个 4 个字节,就好像它是 int 类型一样。

这是否意味着 char 的长度实际上不是 1 字节,ascii 使它看起来像 1 字节?


也许高三个字节变成0xFFFFFF的原因需要更多解释?

由于符号扩展,为 *s 打印的值的高三个字节的值为 0xFF。

The char传递给 printf 的值被扩展为int在致电之前printf.

这是由于 C 的默认行为造成的。

在缺少...之下signed or unsigned,编译器可以默认解释char as signed char or unsigned char。除非使用命令行选项或编译指示显式更改,否则它始终是其中之一。在这种情况下我们可以看到它是signed char.

在缺乏更多信息(原型或强制转换)的情况下,C 通过:

  • int, so char, short, unsigned char unsigned short被转换为int。它从不传递 char、unsigned char、signed char,作为单个字节,它总是传递int.
  • unsigned int大小与int所以该值不加改变地传递

编译器需要决定如何将较小的值转换为int.

  • signed值:的高字节int是从较小值扩展的符号,这有效地向上复制顶部符号位以填充int。如果较小的有符号值的最高位为 0,则高位字节填充为 0。如果较小的有符号值的最高位为 1,则高位字节填充为 1。因此 printf("%x ",*s ) 打印 ffffffc2
  • unsigned值没有符号扩展,int 的高字节是“零填充”

因此,C 可以调用没有原型的函数(尽管编译器通常会对此发出警告)

所以你可以编写并期望它运行(尽管我希望你的编译器发出警告):

/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */

int main (int argc, const char * argv[]) {
    signed char schar[] = "\x70\x80";
    unsigned char uchar[] = "\x70\x80";

    printf("schar[0]=%x schar[1]=%x uchar[0]=%x uchar[1]=%x\n", 
            schar[0],   schar[1],   uchar[0],   uchar[1]);
    return 0;
}

打印:

schar[0]=70 schar[1]=ffffff80 uchar[0]=70 uchar[1]=80

The char我的(Mac 的 gcc)编译器将值解释为signed char,因此编译器生成代码来签名扩展char to the int beforeprintf 调用。

如果有符号字符值设置了最高(符号)位 (\x80),则转换为int标志延伸了char价值。符号扩展填充高字节(在本例中,另外 3 个字节构成 4 字节)int) 与 1,由 printf 打印为 ffffff80

当有符号字符值的顶部(符号)位被清除(\x70)时,转换为int仍然标志延伸char价值。在本例中,符号为 0,因此符号扩展用 0 填充高位字节,printf 将其打印为 70

我的示例显示了该值的情况unsigned char。在这两种情况下,该值未进行符号扩展,因为该值是unsigned。相反,它们被扩展为带有 0 填充的 int。 printf 可能看起来只打印一个字节,因为该值的相邻三个字节将为 0。但它正在打印整个int,恰好该值为 0x00000070 和 0x00000080,因为unsigned char值被转换为int没有符号扩展。

您可以通过使用合适的格式 (%hhx) 强制 printf 仅打印 int 的低字节,因此这会正确打印原始 char 中的值:

/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */

int main (int argc, const char * argv[]) {
    char schar[] = "\x70\x80";
    unsigned char uchar[] = "\x70\x80";

    printf("schar[0]=%hhx schar[1]=%hhx uchar[0]=%hhx uchar[1]=%hhx\n", 
           schar[0],   schar[1],   uchar[0],   uchar[1]);
    return 0;
}

这打印:

schar[0]=70 schar[1]=80 uchar[0]=70 uchar[1]=80

因为 printf 将 %hhx 解释为将 int 视为unsigned char。这不会改变在调用 printf 之前 char 已符号扩展为 int 的事实。它只是告诉 printf 如何解释 int 内容的一种方法。

在某种程度上,对于signed char *schar, 的含义%hhx看起来有点误导,但 '%x' 格式解释int as unsigned无论如何,并且(使用我的 printf)没有格式可以打印带符号值的十六进制(恕我直言,这会令人困惑)。

遗憾的是,ISO/ANSI/... 并没有自由发布我们的编程语言标准,因此我无法指出该规范,但在网络上搜索可能会找到工作草案。我没有尝试去寻找他们。我推荐 Samuel P. Harbison 和 Guy L. Steele 编写的《C: A Reference Manual》作为 ISO 文档的更便宜的替代品。

HTH

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gcc 内部使用相同的位表示 int 和 char 吗? 的相关文章

随机推荐

  • 在 Unix 中,如何删除当前目录及其下面的所有内容?

    我知道这会删除子目录及其下面的所有内容 rm rf
  • 提高大型结构列表的二进制序列化性能

    我有一个以 3 个整数保存 3d 坐标的结构 在测试中 我将 100 万个随机点放在一起 List 然后对内存流使用二进制序列化 内存流大小约为 21 MB 这似乎非常低效 因为 1000000 点 3 坐标 4 字节应该至少为 11MB
  • iphone总是返回UIInterfaceOrientationPortrait

    我需要确保当我的UIViewController负载 它根据需要旋转 我已经实施了shouldAutorotateToInterfaceOrientation方法及其所有工作正常 除非应用程序首次加载时 当 iphone 处于横向模式时 或
  • JavaScript Intellisense 在 Visual Studio 2015 中不起作用

    我知道这个问题在网上以及整个网络上都有很多重复的问题 不幸的是 所提出的建议都不起作用 除了重新安装 VS 15 之外 我已经完成了所有操作 如果我可以帮助的话 我宁愿不这样做 我去过的一个网站 references js 背后的故事 ht
  • VBA - 循环遍历表单上的控件并读取值

    我想循环遍历表单上的控件并读取值 但是 Value 和 Checked 属性不可用 我的问题是 当我循环访问控件 在本例中为复选框 时 如何读取它们的值 Dim Ctrl as Control For Each Ctrl In frmMai
  • 指针问题! (安卓)

    我在 onTouch 方法中遇到多个指针的问题 所有指针都与一个布尔值相关联 如果向下则为 true 如果向上则为 false 非常重要的是 如果一个指针从 true 变为 false 它不会影响其他布尔值 我遇到的问题是 例如 当指针 1
  • JSON.NET 序列化 JObject,同时忽略 null 属性

    我有一个JObject它被用作template用于调用 RESTful Web 服务 这JObject通过解析器创建 并且由于它用作模板告诉用户端点架构是什么样子 所以我必须找到一种方法来保留所有属性 这就是为什么我将它们的值默认为null
  • 如何提高MySQL INSERT和UPDATE性能?

    我们数据库中的 INSERT 和 UPDATE 语句的性能似乎正在下降 并导致我们的 Web 应用程序性能不佳 表是InnoDB 应用程序使用事务 我可以做一些简单的调整来加快速度吗 我认为我们可能会遇到一些锁定问题 我怎样才能找到答案 你
  • iOS:iOS 4.3 和 5.0 之间不同的 addSubview 行为

    之前在 iOS 4 3 中编码时 我发现将视图控制器的视图添加到另一个视图时 superview addSubView controller view 控制器实例将不会收到 viewWillAppear viewDidAppear消息 比我
  • 带有 wsdl2java 插件的 gradle

    我正在使用 no nils wsdl2java 插件 完整的 gradle build 文件如下所示 plugins id org springframework boot version 2 3 4 RELEASE id io sprin
  • 通过网络共享的 SQL CE

    我之前见过这个问题 但找不到关于什么是可能 不可能以及什么解决方法可能可用的明确解释 我有一个现有的 C 应用程序 它使用 SQL CE 来存储本地信息 该数据库只能由单个应用程序访问 并存储在用户的 appdata 文件夹中 某些环境将
  • setInterval 会导致浏览器挂起吗?

    几年前 我被警告不要使用setInterval很长一段时间 因为如果被调用的函数运行时间超过指定的时间间隔 可能会导致浏览器挂起 然后无法跟上 setInterval function foo bar i 1 现在 我知道在循环中添加大量代
  • 使用地理编码发出一个请求后超出查询限制

    我正在使用 ggmap 的地理编码来查找不同城市的纬度和经度 昨天它工作得很好 但今天只发出一个请求后我就收到了 OVER QUERY LIMIT 事实上 如果我只是加载库并运行地理编码 它会抛出 OVER QUERY LIMIT 错误 g
  • 链表迭代器实现 C++

    我已经在 C 中创建了一个链接列表 并想为其实现一个迭代器 以便我可以执行范围循环 for const int i list where Linked List
  • 将 csv 文件转换为 pandas 数据框

    我有一个以下格式的 CSV 文件 DATES 01 12 2010 01 12 2010 01 12 2010 02 12 2010 02 12 2010 02 12 2010 UNITS Hz kV MW Hz kV MW Interva
  • 如何在 Django URLpatterns 中调度请求方法?

    很清楚如何创建从 URL 正则表达式分派的 URLPattern r books books where books可以根据请求方法进一步调度 def books request if request method POST else 我想
  • 如何从Python文件中查找每个工作角色的平均工资

    我想写一个python代码来查找平均工资对于每种类型的工作角色 我认为您这样做是为了学习如何使用 Python 编写此类代码的练习 那么这种仅使用基本 Python 命令和类型的方法应该会有所帮助 read file content wit
  • 搜索具有多个值的多列 SQL

    我知道可以用一个值搜索多个列 我想在 3 4 列中搜索 4 个或者 5 个值 我想检查我选择的任何列是否具有特定值 Example Column 1 Column 2 Column 3 Column 4 Hello True Goodbye
  • OCaml 3.12 中的一流模块:它们将使哪些事情变得更容易(或可能)?

    我听说 OCaml 3 12 中即将推出 一流模块 他们将提供什么优势 哪些孩子的事情会变得更容易 他们试图解决什么问题 一个简单的例子就足够了 这只是一个可能的应用程序 但一流的模块可以轻松地对存在类型进行编码 基本上是一个模块打包存在类
  • gcc 内部使用相同的位表示 int 和 char 吗?

    我只是为了好玩而玩弄 unicode 字符 不使用 wchar t 支持 我只使用常规的 char 数据类型 我注意到 当以十六进制打印它们时 它们显示了完整的 4 个字节 而不是仅一个字节 对于前 考虑这个 c 文件 include