qlb1234 发表于 2009-12-18 18:22:31

慎用AVR Studio 4.18,有不完善之处(详见6楼)

如果C文件函数里的参数与其对应的头文件里描述得不一样,则会导致参数传递不成功,但函数照常执行。编译时,不会给出提示。
举个例子,a.c和a.h。
a.c:
void abc(unsigned char x)
{
……
}
a.h:
void abc(unsigned long x);
abc()里的语句会照常执行,但x永远是0。编译环境:AVR Studio 4.18、WinAVR 20090313、ATmega168。

我记得4.17是绝对会提示的。
发现这个漏洞的来响应一下。

qlb1234 发表于 2009-12-18 18:41:00

刚刚装了SP1,版本变成Build 692,问题依旧。

snoopyzz 发表于 2009-12-18 18:42:51

你不会是关了warning吧?
再说了,这有问题也是winavr的事,关avrstudio什么事?

qlb1234 发表于 2009-12-18 19:10:12

回2楼,我一直用WinAVR 20090313。在换成4.18前,从未遇到过这种情况。
警告能关掉吗?请问怎么关?

voidx 发表于 2009-12-18 19:51:44

楼主吧工程上传上来看看。

qlb1234 发表于 2009-12-18 20:09:40

点击此处下载 ourdev_516329.rar(文件大小:15K) (原文件名:1.rar)

工程在此,请大侠们验证。
拿串口观察。若不改动a.h,则显示00。若把a.h的“void a(unsigned long x);”改为“void a(unsigned char x);”,则正常。
USART.c是串口的驱动,用其它型号的话,换成自己的就行。

aozima 发表于 2009-12-18 20:34:00

因为AVR一个寄存器不够LONG这么宽.....
以long传进去 函数得到的只是最高字节(同时可猜:avr-gcc传递参数时高字节在低号寄存器)
如果你在a.c里面include a.h是会有警告的

如果在32位机上面 这样做不会出错(前提是:参数范围在0~0xFF)

漏洞在你自己 和前几天那个函数不写return而无视警告却怪运行正确的人有得一比.

(以上内容仅是猜测 本人不负责)

qlb1234 发表于 2009-12-18 20:50:34

回6楼,不在a.c里面包含a.h里,的确不会产生警告。包含了,那肯定是有警告的。我承认我疏忽了这一点。
但是这样一来,一个C文件对应一个头文件就没有意义了。反正两个定义可以不一样,乱写它也不会提示。
打个生动的比方,主函数去商店买东西,头文件说这个函数是两斤重的。结果从仓库里提了货,一称,只有半斤。每次都要仓库监督着头文件,岂不是很累?

Gorgon_Meducer 发表于 2009-12-18 21:00:38

LS你终于理解到了
C语言本身就允许欺骗的……

我就经常利用这个特性……
为了屏蔽某些内容,我经常给不同的“客户”——也就是别的.c模块,不同的.h……

类型……大小……XXXX都可以骗得……

aozima 发表于 2009-12-18 21:02:21

"在a.c里面include a.h"

是非必要的部分
理论上
a.c要不要写一个a.h也是非必要部分

但不管如何 写一个正确无误的程序是你要做的

qlb1234 发表于 2009-12-18 21:04:37

谢谢楼上各位大侠,以后一定多加注意。
问8楼,比如说呢?可以拿来干吗?

qlb1234 发表于 2009-12-18 21:06:02

【9楼】 aozima
但不管如何 写一个正确无误的程序是你要做的
-----------------------------------------
说得对。以前一直没出现过不包含的情况。这次真的是大意了。

Gorgon_Meducer 发表于 2009-12-18 21:16:19

比如,你这个.c里面有一个结构题,这个结构体里面保存了很重要的数据,
按道理只能由这个.c来处理。
但是,你的这个模块,团队里面的其他人也要用,于是,你就需要给他们一个.h文件,和.a文件。
问题在于,.h文件里面必须要包含着个结构体,否则别人无法使用你这个模块,比如,有一个初始化
函数,根据用户的基本输入,初始化,返回一个这样的结构体;还有一些函数需要以这个结构体作为
输入参数。你要注意,尽管用户不需要知道结构体的内容,也不应该自己访问结构体的成员变量,但
是它至少是一个比不可少的类型,用来在函数之间传入传出……
可怕的事情发生在不知情的同事有一天发现,直接修改结构体变量的某个成员很方便就能实现某个功能……
灾难由此开始……你的库函数被绕开了,最关键的是,某些被隐藏在.a里面的操作也被绕开了……于是
原本天衣无缝的逻辑被撕扯了……

如何防止别人直接访问结构体?当然是让结构体变成板转啦!比如:看下面的例子

typedef struct
{
    unsigned char StructMask[sizeof(
      struct _
      {
            ...这里填放原来这个结构体应该有的内容
      })];
}NAME;

是不是很贼啊?
这种技术叫做掩码结构体

aozima 发表于 2009-12-18 21:20:55

"以前一直没出现过不包含的情况"能不包含的情况下尽量不包含

qlb1234 发表于 2009-12-18 21:23:59

大体上明白,改天实践一下。

qlb1234 发表于 2009-12-18 21:25:24

【13楼】 aozima
能不包含的情况下尽量不包含
---------------------------
包含了,不是利大于弊吗?

wangxiaoacc 发表于 2009-12-18 21:28:46

这个帖子因傻孩子的回复而精彩,书上看不到的用法呀。

steven 发表于 2009-12-18 21:43:41

MARK

z_zt 发表于 2009-12-18 21:51:44

傻孩子太COOL了,但愿能早日见到你的《AVR32 UC3工程师快入门指南》

voidx 发表于 2009-12-19 09:07:11

你要注意,尽管用户不需要知道结构体的内容,也不应该自己访问结构体的成员变量,但
是它至少是一个比不可少的类型,用来在函数之间传入传出……
----------------------------------------------------------------------------------

如果不想别人知道你结构体类容,直接把结构体定义到C文件里(或者一个单独的头文件,只给自己用,不公开)
公开的头文件传递指针全部用 void *指针。

如果需要用户定义结构体变量,在公开的头文件全部定义成数组,用户只要传递数组名就行了。
用户的感觉是完全不涉及结构体,没有任何形似的结构体和结构体操作,
传递指针全部用void *指针。至于void *指针的具体含义,是有你的函数来解释的,这部分函数做成库文件,
对方也看不到的。


我的ID是voidx(void *),在C语言里最喜欢用的就是void *指针了。
(当一个指针不指向任何类型,换句话,也可以说,这个指针指向任意类型)

cyberjok 发表于 2009-12-19 10:09:02

楼上的方法才是正道!

windy__xp 发表于 2009-12-19 11:17:34

傻孩子的方法,可以有效拒绝接修改结构体变量,但是自己用起来肯定也很头大。19L 才是正道,个人也很喜欢 void *,不指向任何类型,同时可以指向任何类型。

marshallemon 发表于 2009-12-19 12:34:40

mark

PV-BAT-LOAD 发表于 2009-12-19 12:50:14

bj

z_zt 发表于 2009-12-19 15:12:47

上官大侠能不能给你实例看看,谢谢

Gorgon_Meducer 发表于 2009-12-19 16:01:25

to 【19楼】 voidx void *
    此方法太危险。我这么做的好处是,给别人一个基本的安全信息:
    在C语言中安全的处理数据起码需要两个基本元素:
    1、起始地址
    2、大小

    如果这两个信息编译器都能在编译时刻验证和检测,那么可以避免很多潜在的问题。
    如果把这两个信息中的大小抹去(由使用者和客户人为约定,而不使用技术上的约束),代码本身
就是拥有风险的。我把这类代码称为“信用代码”。
    void *是不能sizeof的……

关于掩码结构体,可以用下面的宏来实现

# define MASKED_STRUCT(__CONTENT)\
            struct\
            {\
                unsigned char MaskStruct;\
            }

使用的时候和typedef 一起用,比如
typedef MASKED_STRUCT
(    //注意这里是圆括号
    ...这里填写结构体的内容
) EXMPLE_TYPE_NAME;


还有,如果我觉得某个代码结构用起来复杂,我一定会编写对应的宏的……这就是为什么我的
代码里面那么多宏……

to 【21楼】 windy__xp 龙啸
   忘记说了…….c里面有一个没有mask过的结构体,这个.c是不会去包含那个欺骗后的.h的。

wc8841484 发表于 2009-12-19 16:13:53

太强大了   COOL呢

wjc1956 发表于 2009-12-19 17:48:51

mark

windy__xp 发表于 2009-12-19 18:59:07

【25楼】 Gorgon Meducer 傻孩子
------------------------------
    学习了,C的确太灵活了。

    同时由于C的灵活,稍微不注意,就会带来一些意想不到的错误,从这一点上来说,还是感觉汇编驾驭起来更“踏实”,虽然麻烦,^_^

    说个最近遇到的事,最近移植uCOS II 到XMEGA,虽然移植函数写完了,后来发现实际应用不太方便,于是自己写了个简单的时间片轮转调度的核,时间片定时中断用 naked 申明不保护现场,如下:
    void TCC0_OVF_INT( void ) __attribute__ ( ( signal, naked ) );

    ISR( TCC0_OVF_INT )
    {
      asm volatile(" PUSH R0 " );    // 时间片中断,系统任务调度,保存所有的寄存器
      ……
      asm volatile(" POPR0 " );
    }

    后来调试,任务调度总是有问题,后来看汇编代码,发现 TCC0 中断没有返回,后来查资料才知道 这个“裸体”实在太彻底了,需要人工加入 reti 指令,如下:

    ISR( TCC0_OVF_INT )
    {
      asm volatile(" PUSH R0 " );    // 时间片中断,系统任务调度,保存所有的寄存器
      ……
      asm volatile(" POPR0 " );
      asm volatile(" RETI    " );
    }

plc_avr 发表于 2009-12-19 19:44:02

刚下了studio418,受教了。

lgx0301 发表于 2009-12-19 19:48:52

想裸奔那你就得自己手工加reti

cyberjok 发表于 2009-12-19 20:30:00

如果结构体的内容,不让客户知道,那就不存在客户调用传递或返回这种结构体了!

voidx 发表于 2009-12-19 21:07:41

gcc裸中断保护现场,还需要把R1清零。

windy__xp 发表于 2009-12-19 21:28:53

32L 什么意思?

xyq4513 发表于 2009-12-24 15:03:04

记号

wzyllgx 发表于 2010-7-8 16:51:04

mark

yaya001 发表于 2010-7-8 17:26:33

mark

xuejianhua1986 发表于 2010-7-8 22:19:21

mark

yarnn 发表于 2011-4-22 18:52:17

mark

Adrian 发表于 2011-4-22 22:31:33

学习。

hecb999 发表于 2011-7-10 12:34:50

mark

aiqinger 发表于 2011-8-25 19:53:39

都是高手呀

davylee 发表于 2011-8-25 22:33:30

觉得还是GCC比较好用

luweixuan 发表于 2011-8-28 22:22:53

mark 结构体掩码

qingaixww 发表于 2011-11-17 21:58:42

太强大了!!!

kd006 发表于 2011-12-13 17:22:58

厉害,刚安装了avr studio 4.18

lz80650904 发表于 2012-2-21 11:29:52

太强大了,看得云里雾里的,不知所云!~

danpianjibb 发表于 2012-5-9 17:17:36

飘过。。。。。。。。。。。。。。。

zhaoxukiller 发表于 2012-10-7 19:16:11

帖子不错!大家回复的都很精彩!谢谢,受用了
页: [1]
查看完整版本: 慎用AVR Studio 4.18,有不完善之处(详见6楼)