GCC编译时char类型默认有无符号探索

本文探讨了在X86_64和ARM_32环境下GCC编译器的配置细节,以及char类型有无符号的默认配置差异。通过代码测试,揭示了char类型不当使用可能导致的内存访问错误,强调了在不同平台进行代码移植时需注意char类型的默认属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

X86_64环境

CentOS版本:CentOS Linux release 7.3.1611 (Core)

gcc 版本: 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)

gcc默认情况下char有符号,默认配置如下:

目标:x86_64-redhat-linux
配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux

代码测试:

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

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

static int save_address[100];
static char call_idx = 0;

int main(void)
{   
	printf("PID=%d\n",(int)syscall(__NR_gettid));
	while(1){
		printf("eason call_idx=%d \n", call_idx);
		save_address[call_idx++%100] = 1;;
	}
}

编译:gcc -Wall -g main.c

[yubo.wang@localhost func-call]$ ./a.out 
PID=82788
eason call_idx=0 
eason call_idx=1 
......
eason call_idx=127 
eason call_idx=-128 
段错误(吐核)

[yubo.wang@localhost func-call]$ gdb a.out core.82788 
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/yubo.wang/4g-box/func-call/a.out...done.
[New LWP 82788]
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000000004005f1 in main () at main.c:17
17			save_address[call_idx++%100] = 1;;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
(gdb) 

save_address[-28]怎么就引起进程崩溃退出了呢?查看上面的gdb信息可以看到触发了段错误,访问了非法内存,-28的内存地址是多少呢?

全局或静态局部变量容易(save_address[-25])引起访问非法内存,局部变量就不容易(save_address[-2095653])引起崩溃,这是为何?

需要看下《程序员的自我修养-链接、装载与库》才能解开心中疑惑啊。

编译时可添加参数设置char类型有无符号:-fsigned-char/ -funsigned-char

ARM_32环境

arm-linux-gnueabihf-gcc默认配置如下:

Configured with: /cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/src/gcc-linaro-4.9-2014.07/configure --build=i686-build_pc-linux-gnu --host=i686-build_pc-linux-gnu --target=arm-linux-gnueabihf --prefix=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/install --with-sysroot=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/install/arm-linux-gnueabihf/libc --enable-languages=c,c++,fortran --disable-multilib --enable-multiarch --with-arch=armv7-a --with-tune=cortex-a9 --with-fpu=vfpv3-d16 --with-float=hard --with-pkgversion='crosstool-NG linaro-1.13.1-4.9-2014.07 - Linaro GCC 4.9-2014.07' --with-bugurl=https://bugs.launchpad.net/gcc-linaro --enable-__cxa_atexit --enable-libmudflap --enable-libgomp --enable-libssp --with-gmp=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-mpfr=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-mpc=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-isl=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-cloog=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-libelf=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --enable-threads=posix --disable-libstdcxx-pch --enable-linker-build-id --enable-plugin --enable-gold --with-local-prefix=/cbuild/slaves/oorts/crosstool-ng/builds/arm-linux-gnueabihf-linux/install/arm-linux-gnueabihf/libc --enable-c99 --enable-long-long --with-mode=thumb --disable-multilib --with-float=hard

char类型默认无符号的,代码验证如下:

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

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

static char call_idx = -1;

int main(void)
{   
	printf("PID=%d\n",(int)syscall(__NR_gettid));

	if( call_idx < 0 ) {
		printf("default signed call_idx=%d\n",call_idx);
	}
	else {
		printf("default unsigned call_idx=%d\n",call_idx);
	}
	return 0;
}
root@www:~# ./a.out 
PID=14177
default unsigned call_idx=255

这是为何呢? 难道与gcc版本有差异,原因未知。

其他类型默认都是有符号的,如:short,int,long。

所以在使用返回值类型定义时最好用int类型,防止默认无符号导致问题。

使用char类型时,最好使用typedef重定义,防止差异性,也会提高代码的移植性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值