首页 > 其他分享 >在 ISO C90 标准中 C 语言负数比正数大?

在 ISO C90 标准中 C 语言负数比正数大?

时间:2024-10-02 21:33:30浏览次数:7  
标签:main ebp C90 cfi int ISO 2147483647 2147483648 正数

演示环境

  • OS: Arch Linux x86_64
  • Kernel: Linux 6.10.10-arch1-1
  • GCC: 14.2.1

演示代码

int main(void)
{
	return -2147483648 < 2147483647;
}

编译和链接

gcc -std=c90 -m32 main.c # 添加 -masm=intel 选项可以生成 intel 语法的汇编

gcc 输入警告:

warning: this decimal constant is unsigned only in ISO C90

运行并查看结果

./a.out
echo $?

输出结果为:0

先看一下编译生成的汇编代码

  1. 执行命令
gcc -S -std=c90 -m32 main.c
  1. 生成的汇编代码如下(只截取了 main 标号部分):
main:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	call	__x86.get_pc_thunk.ax
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	movl	$0, %eax # 11 行
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:

看一下第 11 行汇编指令 movl $0, %eax,返回值 0 是 gcc 在编译阶段计算(优化)的结果(意料之中!特别是现代编译器,哪怕是在默认的优化级别下,也没理由不进行优化)。

关于 ISO C90 标准

在 ISO C90 标准中,-2147483648 是由一个负号和 2147483648 两部分组成。根据 C90 标准的规定,整数常量(不带后缀)会根据其大小自动决定是 int 类型、long int 类型还是 unsigned long int 类型。

2147483648 超出了 32 位 int 的最大范围(2147483647),因此编译器会把它当成 unsigned long int 类型。所以,-2147483648 其实是 - 和一个 unsigned long int 类型 2147483648 组成,因为这里的负号是尝试对一个无符号数取负,这将引发类型问题,这样的操作在 C 语言中是合法的,但会导致值的环绕(wrap around),最终得到一个很大的正数。

解决办法

  1. 以两个数相减的表达式来代替 -2147483648

既然问题出在 -2147483648 的绝对值太大了,如果将 -2147483648 改为其它的表达式形式,只要表达式的结果不变且表达式中的每个子表达式不超出范围不就变小了吗?这里以表达式 -2147483647 - 1 进行演示:

int main(void)
{
	return (-2147483647 - 1) < 2147483647;
}

重复之前的编译链接步骤,发现不但没有了警告,而且运行的结果也是对的。

  1. 分别使用宏代替 -21474836482147483647
#include <limits.h>

int main(void)
{
    return INT_MIN < INT_MAX;
}

我们知道宏是在预处理(预编译)阶段进行处理(替换)的,那么宏 INT_MININT_MAX 会分别替换成什么呢?

使用命令 gcc -E -std=c90 -m32 main.c 预处理的结果为(只截取了关键部分):

int main(void)
{
    return (-0x7fffffff - 1) < 0x7fffffff;
}

-0x7fffffff0x7fffffff 不就分别是 -21474836472147483647 的十六进制形式吗?所以,方法 1 和 2 本质是一样的。

  1. 使用变量(不推荐)
int main(void)
{
	int min = -2147483648;
	return min < 2147483647;
}

依然有相同的警告,但结果(1)居然是对的?还是先看一下编译生成的汇编代码(同样只截取关键部分):

main:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$16, %esp
	call	__x86.get_pc_thunk.ax
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	movl	$-2147483648, -4(%ebp)
	cmpl	$2147483647, -4(%ebp)
	setne	%al
	movzbl	%al, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc

movl $-2147483648, -4(%ebp) 的意思是将 -2147483648 压栈,其实就是放到内存中,由于 -2147483648 是负数,在内存中存放的是补码形式(也就是十六进制的 0x80000000)。

cmpl $2147483647, -4(%ebp) 的意思是比较 2147483647(十六进制为 0x7FFFFFFF)和 0x80000000 的大小,比较的结果存放到标志寄存器的对应位中。

setne %al 的意思是如果比较的结果为不相等(明显 0x7FFFFFFF 和 0x80000000),将 al 寄存器置 1(二进制表示为:0000001

movzbl 指令负责拷贝一个字节,并用 0 填充其目的操作数中的其余各位。因此,movzbl %al, %eax 指令执行后,寄存器 eax(也就是返回值)为 0x00000001

标签:main,ebp,C90,cfi,int,ISO,2147483647,2147483648,正数
From: https://www.cnblogs.com/escwqa/p/18445113

相关文章

  • 进程管理工具:非daemon进程管理工具supervisor
    一、非daemon进程管理工具:supervisorWindows安装supervisorhttps://pypi.org/project/supervisor-win/4.5.0/#files 一)进程管理supervisor简介supervisor是一个Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序。supe......
  • buuctf pwn jarvisoj_level01
    首先,将下载的文件用checksec检查一下然后我们将其放入ida64中,按tap键查看源码点开vuln函数,看见有read,buf,发现buf占0x80空间,而,read里面有0x200,所以会有溢出。这里显示buf的地址为0x80+8,即136。然后有发现有system函数那就简单多了,它的起始地址为0x400596接下来写代码......
  • ISO/IEC/IEEE 29119-1:2022(E) 系统与软件工程软件测试第1部分:概念和定义
    0前言国际标准化组织(ISOtheInternationalOrganizationforStandardization)和国际电工委员会(IECtheInternationalElectrotechnicalCommission)构成了世界标准化的专门体系。作为国际标准化组织或国际电工委员会成员的国家机构通过各自组织设立的技术委员会参与国际标准的......
  • 事务 Atomicity Consistency Isolation Durability
    事务分类:原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability)。原子性:(Atomicity)被执行的事务要么全部成功,要么全部失败,不能只单独执行一个。例如:有两个用户A和B,A原本有1000元,B原本有500元,A向B转账200元,将执行A变成800元和B变成700元,或者A不变并且B也不变,这两......
  • mysql数据库 - anolisos安装
    文章目录一、anolisos系统介绍1.1、anolisos系统的起源1.2、anolisos系统的版本支持1.3、anolisos系统的特点1.4、anolisos系统的适用场景二、环境部署2.1、修改主机名2.2、修改静态ip地址2.3、关闭selinux2.4、关闭或放通防火墙端口三、安装mysql数据库3.1、更新yum源......
  • 深入了解ISO 10012测量管理体系认证
    在当今快速发展的市场环境中,企业面临着越来越高的质量管理和测量要求。ISO10012测量管理体系认证应运而生,旨在帮助企业建立一套系统的测量管理流程,确保其测量过程和测量设备的准确性与可靠性。这一认证不仅对企业的内部管理有着深远影响,也为其在市场竞争中提供了有力支持。ISO100......
  • Ubuntu 通过Supervisor 或者 systemd 管理 .Net应用
    在Ubuntu上安装.NET8.0,通过supervisor或systemd管理.NET应用服务,确保应用能够自动启动、运行以及在崩溃时重启。1.安装.NET8.0最新的Ubuntu版本已经不需要注册Microsoft包存储库了,具体的可以参考微软官方文档安装,在Ubuntu上安装.NETSDK或.NET运行时2.使用Sup......
  • 道路车辆功能安全 ISO 26262标准(2)—功能安全管理
    写在前面本系列文章主要讲解道路车辆功能安全ISO26262标准的相关知识,希望能帮助更多的同学认识和了解功能安全标准。若有相关问题,欢迎评论沟通,共同进步。(*^▽^*)1.道路车辆功能安全ISO26262标准2.ISO26262-2 功能安全管理ISO26262是IEC61508对E/E系统在道路车......
  • 什么情况下需要 new Date().toISOString()?,是否会受时区的影响吗?
    newDate().toISOString()是JavaScript中用于获取当前日期和时间的ISO8601格式字符串的方法。格式为YYYY-MM-DDTHH:MM:SS.sssZ。这种格式的字符串在很多场景中都非常有用,特别是在需要标准化日期和时间表示的情况下。以下是一些常见的使用场景:1.API通信在与后端API通......
  • ISO 9001认证:企业腾飞的品质基石
    ISO9001是由国际标准化组织(ISO)制定的质量管理体系标准,旨在为企业提供一套全面的质量管理框架。它不仅帮助企业提升产品和服务的质量,还通过精细化的管理方法,推动企业整体运作更加规范和高效。与其说ISO9001是一个简单的认证,不如说它是一种全球公认的管理哲学,帮助企业在市场竞争中......