微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 硬件电路设计 > 硬件电路设计讨论 > COSMIC真是个神奇的编译器

COSMIC真是个神奇的编译器

时间:12-13 整理:3721RD 点击:
如果你调用了一个函数,但是没有显示extern声明,编译器不会报错,正常编译通过。
然后运行时错误。相当于它会帮你猜一个函数参数。能正确就怪了。
COSMIC编译器约定:单个8位函数参数,用A寄存器传递,单个16位参数,用X寄存器。
下面的函数,
extern void Fill(uint8_t ucData);
如果用 Fill(0x00);调用,必然出错。
调用时会把参数放到X,然后在函数里面用A寄存器的值。
这些问题想查出来基本上除了跟踪汇编指令没啥好办法,用一次骂一次。

有没有个类似-Wall的选项呢...

gcc也是这么干的啊,但gcc默认会有个warning。
举个例子:
$ cat a.c
int add(char a, char b){
  return a+b;
}
$ cat b.c
#include <stdio.h>
main(){
  printf("add:%d\n", add(300,2));
}
$ gcc a.c b.c -o a
b.c:4:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main(){
^~~~
b.c: In function ‘main’:
b.c:5:22: warning: implicit declaration of function ‘add’ [-Wimplicit-
function-declaration]
   printf("add:%d\n", add(300,2));
                      ^~~
$ ./a
add:46

这是古老的c标准,函数变量不用声明随便用。。

用pclint检查一下

gcc是正常的编译器,正常的编译器都是这样。
你的例子里面,实参300明显超过char的范围了,会发生截断。
COSMIC的神奇之处在于,你即使add(30,2)这样调用,也会出错,
它依然会认为30是int16_t,然后放到X寄存器里面,函数内部再从A寄存器取值。

我觉得肯定不会截断...
不申明接口直接调用,那c就给你默认声明一个类型而已。
所以这里肯定是有个溢出然后越界的,只不过我懒的去看汇编...

你这个例子是没问题的,300+2本来应该是302
由于截断,300=0x012C,截断成char就变成0x2C=44,44+2=46
结果都是可以预知的。和COSMIC那个不是一回事。

我之前也遇到了这个问题,后来函数参数一律不用16位的了

不不,
编译的过程是
a.c->a.o
b.c->b.o
然后再把a.o和b.o链接起来。
在编译a.o的时候因为没有申明add函数,所以其实并不知道它到底是什么类型的。gcc自
己脑补了一个int类型,然后直接把0x012c压入堆栈。
当然执行起来没问题,那是因为在add取值的时候按照char截断了。
此外gcc实际上并没有用堆栈传值,而是用寄存器传值的。如果参数足够多到必须用堆栈
传值,那就有可能出问题了。所以结果依然应该认为是未定义的。事实上要出错也很容
易,改成这样就挂了,而且这个错误在实际coding过程中偶尔是会犯的。
$ cat a.c
int add(float a, float b){
  return a+b;
}
$ cat b.c
main(){
  printf("add:%d\n", add(100,200));
}
$ gcc a.c b.c -o c
$ ./c
add:0

默认类型是int啊

gcc用寄存器传值也是在寄存器够多的cpu上吧...
stm8这种场合不太可能, 一共就几个寄存器

那肯定...
其实我一开始就像构造个用堆栈传然后传出问题的例子出来...
发现死活构造不出来...
一看汇编一口老血...没想到现在不加编译器优化也会默认这么干...
我记得在我小时候很容易搞崩的...

还是严格声明一下比较好

单片机堆栈很小,单片机寄存器很少,
所以呢?这不是很显然的嘛。

avr-gcc似乎是默认int的, avr-gcc的int是16位
有空了写个程序验证一下~

int是跟着系统位宽走的~

avr是8位啊

对哦...
我查了下,根据Programming languages -- C,有这样的说法:
From Section 6.2.5 Types, p5
5 An object declared as type signed char occupies the same amount of storage
as a ''plain'' char object. A ''plain'' int object has the natural size
suggested by the architecture of the execution environment (large enough to
contain any value in the range INT_MIN to INT_MAX as defined in the header
<limits.h>).
And 5.2.4.2.1 Sizes of integer types <limits.h> p1
Their implementation-defined values shall be equal or greater in magnitude
(absolute value) to those shown, with the same sign.
...
minimum value for an object of type int
INT_MIN -32767 // -(215 - 1)
maximum value for an object of type int
INT_MAX +32767 // 215 - 1
Then in those platforms, int must be at least 16 bits

这个不必然。
int最小是16位的,大了不限……

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top