免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: pmerofc
打印 上一主题 下一主题

有此一说:“C不过也是山寨版的Pascal,本质上就是把BEGIN,END变成了花括号” [复制链接]

论坛徽章:
0
121 [报告]
发表于 2011-10-18 18:19 |只看该作者
超越解释器的内存分配只是举个例子
如果只用解释器本身,一样可以做到内存分配,最简单的例子就是开个 ...
ecloud 发表于 2011-10-18 17:28

1 那你是不是否决了你提出的模拟函数的方法?
函数 A                 //  10 ADDA = 123456
{
  int x;                //  20 ADDAX = ADDA + 16
  int y;                //  30 ADDAY = ADDAX + 16
  x=2;                //  40 PEEK(ADDAX,2)
  y=3;                //  50 PEEK(ADDAY,3)
}
2 用分配所有可分配资源的方式来处理模拟函数问题,这动作真不是一般的大。

论坛徽章:
0
122 [报告]
发表于 2011-10-18 18:22 |只看该作者
Watcom的malloc就是返回野地址,所以根本不存在因为“没内存了”的非0,因为永远都分得到。当然这 ...
ecloud 发表于 2011-10-18 17:31

先不管malloc返回值是什么,在你看来
int *a=123456;*a=1;

int *a=malloc(sizeof(int));*a=1;
是不是实质一样的?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
123 [报告]
发表于 2011-10-18 18:45 |只看该作者
回复 88# 幻の上帝

>> 通过语言实现来帮助用户确定一个实体是否需要是一个纯粹静态的类型的实例(用户在声明中只提供一个类型占位符,表示这里的实体自身不是类型,需要作为一个类型的实例),并在实现过程(比如优化)中进一步确定类型模型(这个应该不太现实,至少超过现在静态类型语言实现的能力了)。

这个是与template类似的东西吗? 有哪些不同?
template<typename T/*这个算占位符么?*/>
T max(T,T);

>> 更广范围地说,是通过语言本身重用乃至有限范围内覆盖(用户提供替代品)语言实现的能力。eval是这里另一方面的典型代表(但至少对于C这样的nominal typing的语言来说还不是极致,例如无法直接描述实现中用到的ADT——当然这样的特性应该超过了现在大多数具有思维惯性的用户所期望的了)。

对此lisp程序员感到毫无压力……


>> 现在可以通过命令行调用编译器+动态链接之类的来获得类似效果,但这依赖于环境提供的具体接口,对于语言而言不可控的。
如果将编译+链接+加载作为语言提供的服务之一呢?
比如lua/python程序员就不太会考虑eval究竟是怎么实现、是否可控之类的问题。


>> 而且很要命的是,这些特性更多着眼于功能上而不是整体结构上的补遗,加大了语言的复杂性,使“反紧凑”体现得更加明显,更不容易用对。
>> 另外,无意之中也埋了许多包袱,像constexpr int a = 1;和typedef std::integral_constant<int, 1> a;之间的冗余看样子是永远无法消除的了。
功能上而不是整体结构上的补遗、反紧凑 —— 有这种感觉。
但对于后一个例子, intergal_constaint , 这算是兼容性问题吧? 这东西先在 C++11 之前(没有constexp) 的 boost 中出现了, 难道还被标准化了?


或者换个例子。我是想问问兼容性问题有什么处理方法。
比如 int f(int x, int y);
在C的年代,可能会有其他方案,但应该想不出这方案有什么不好。

直到:
template<typename T, typename U>
/*这里写什么?*/ f(T x, U y);

所以又不得不引入新的语法。但为了兼容性又得支持旧语法 —— 于是语言复杂了、新手迷糊了,为啥这也可以那也行……

完全向后兼容的软件,多演化几个版本,就会越来越臃肿 —— 反例一下子想不出来,正例应该不需要举了。
怎么办。。。


>> 某些能在编译期完全确定逻辑关系的调用(比如scope guard)居然需要依赖于helper class的生存期这种运行期属性(+优化)来控制,而没有更直接明确清晰的方法来表达,或许还让不知情者以为是高深技巧而自以为得计……

你觉得不好的地方是哪个呢:

1. C++03主要是靠析构函数来完成回滚的吧?
{  T g;
} // 这里有 ~T() 的调用
这算是运行期确定还是编译期?

2. const引用提升临时变量生存期
T makeT();
{  T const& g = makeT();
} // 这里有 ~T() 的调用,编译or运行?

3. 派生类到基类引用
D makeD();
{  B const& g = makeD();
} // 这里有 ~D() 的调用,编译or运行?

4. scope guard比上面再增加了一个成员,可以取消~T()中对某个函数的调用……


其实我对scopeguard评价很高的……
insert(pair<int,string>(12,"26")); 比较困难,但可以写
insert(make_pair(12,"26"));
find_if(beg, end, binder< ...  —— 不查资料我真忘这里该怎么写了
find_if(beg, end, bind1st(less<int>(), 12) );  虽然依然别扭,但还是可以写出来的
即使利用函数模板对参数的推导,省去书写类型的麻烦。

但这只对临时变量有用,而临时变量的生命周期太短……
当我想实现一个更范化的rollback方式(为每个需求都写一个class与析构太麻烦),真的就盼着auto赶紧被支持……
直到看见scopeguard……  妈的!原来可以这样!!!

论坛徽章:
1
水瓶座
日期:2014-03-20 18:21:14
124 [报告]
发表于 2011-10-18 19:45 |只看该作者
本帖最后由 ecloud 于 2011-10-18 20:18 编辑
1 那你是不是否决了你提出的模拟函数的方法?
函数 A                 //  10 ADDA = 123456
{
  int  ...
ddddddddd 发表于 2011-10-18 18:19


本来这个例子就是解释PEEK和POKE的用法的,对于你的问题,我说过,可以自行模拟扩展。PEEK和POKE的方法可以用数组代替,当然肯定不如直接实模式内存访问效率高

至于什么动作大不大的问题,本来就是相对的。我说过,一切面向过程的语言都是汇编的马甲,本质上汇编干事情就是大动作,站在TC的角度来看就是如此
如果站在JVM的角度来看,人家还觉得malloc的动作大,**A的动作也大;计算机语言模式的发展就是层层抽象,由编译器/解释器/虚拟机来去越来越多的做原本需要人力去做的事情:
比如Watcom C在实模式下编译,管你用不用malloc都是野内存,一个int i=1;直接就给你从0000开始分配内存(我只是打个比方,具体地址数是个偏移量,基地址是入口地址)。但是前期要求你自己把基本内存的前端都清空,比如把DOS装到上位内存去。所以需要你自己编写一段汇编,检测基本内存的占用情况,如果没清空就直接退出,有足够的内存容量才会去LOAD后面的EXE。这就是很多DOS游戏所采用的办法

TC的壳=BASIC解释器=CALL机器语言子程序,作用是构建出一个内存池给后续的用户程序用。Watcom可以没有这个壳,就是直接从0开始填内存,等价于PEEK(0,1)

当代的系统里面,内存分配都是通过系统调用请求内核来完成的,得到的也都是虚地址数,你想溢出,也是有限的,最多得到些系统漏洞,不可能像实模式那样,可以直接把系统改得面目全非,可以直接控制硬件行为。你可以说这是好处,安全;你也可以说这是坏处,缺乏灵活性

保护模式内存使用,是由硬件和操作系统发展起来的,这并不是C或者C编译器的功劳。业界第一个保护模式、虚拟内存的实现是VMS running on VAX,整个系统都是汇编实现的

好了,科普到此结束,废话我不再说了,有兴趣的可以自己用数组实现一个内存池,什么链表、二叉树都可以基于此实现,这也不是什么新鲜的东西,早在90年代早期就有很多人讨论过这个问题了,这已经是结构化语言诞生早期所热衷讨论的事情了,不知道的只能说你进入这个行业太晚了,呵呵


最后点一点关键的吧,关于内存的问题,是由编译器/解释器/虚拟机来决定的。如果这些工具是野路子,那么你的程序必定是野路子,如果工具本身具有保护性,那么你无论在语言里面怎么折腾都不可能出大格,比如TC里面你不把选项打开,128K是永远不可能卖过去的砍,你&(add+100000000)结果直接编译报错。编译器不进行内存保护,你不能说是这种语言有问题。一个反例就是微软曾经的VJ++,用Java你可以写出来内存溢出的程序来,这是VJ++编译器/编译模式的问题,而不是Java本身的问题,Java规定要在VM里跑,你编译成本地代码,自然要承担这个风险了。原本由VM去做的内存保护工作,如今就要自己想办法。不是说某个语言有了malloc,有了GC,就一劳永逸的解决内存问题了,这还要看这malloc,GC究竟是怎么实现的

论坛徽章:
0
125 [报告]
发表于 2011-10-18 19:52 |只看该作者
本帖最后由 幻の上帝 于 2011-10-18 20:07 编辑

回复 123# OwnWaterloo

>> template<typename T/*这个算占位符么?*/>
----
算,但局限性太大了。
1.这里T是typename……那么template class T<class>之类的呢。
2.模版实例化的phase是被明确规定的,照着现有的编译型实现来说,也就是语言的实现无权把template保留在最终的目标文件中,也无法有效地避免自身语义上没有改变的模版被重新编译。
====
>>对此lisp程序员感到毫无压力……
----
就是照着Lisp说的……不过前提是得适应一堆括号……= =
其实我觉得Lisp的潜力远远不止作为一种programing language。可惜没什么NB的人来实现并引起足够的关注。
====
>>如果将编译+链接+加载作为语言提供的服务之一呢?
----
那也可以,如果标准能下决心保证一个实现必须提供这样的服务的话。
====
>> 但对于后一个例子, intergal_constaint , 这算是兼容性问题吧? 这东西先在 C++11 之前(没有constexp) 的 boost 中出现了, 难道还被标准化了?
----
integral_constant 真被标准化了……而且被其它部分用到,比如tuple_size就是继承了它的实例。
兼容性是重要的原因,不过我这里更想说的是核心语言特性的时候对可能造成的冗余关注得不够。
====
>> 或者换个例子。我是想问问兼容性问题有什么处理方法。
在C的年代,可能会有其他方案,但应该想不出这方案有什么不好。
直到:
template<typename T, typename U>
/*这里写什么?*/ f(T x, U y);

所以又不得不引入新的语法。但为了兼容性又得支持旧语法 —— 于是语言复杂了、新手迷糊了,为啥这也可以那也行……

完全向后兼容的软件,多演化几个版本,就会越来越臃肿 —— 反例一下子想不出来,正例应该不需要举了。
怎么办。。。
----
……或许是我不够乐观,或许真没办法了。也许自C开始(或者更早,BCPL,但没有很流行,可以不算)就注定无可救药了。
无论是设计软件还是语言,精确了解未来的需求需要非凡的前瞻能力。这种时间跨度上大家都做不好,也没办法。
====
>> 你觉得不好的地方是哪个呢:
1. C++03主要是靠析构函数来完成回滚的吧?
{  T g;
} // 这里有 ~T() 的调用
这算是运行期确定还是编译期?

2. const引用提升临时变量生存期
T makeT();
{  T const& g = makeT();
} // 这里有 ~T() 的调用,编译or运行?

3. 派生类到基类引用
D makeD();
{  B const& g = makeD();
} // 这里有 ~D() 的调用,编译or运行?
4. scope guard比上面再增加了一个成员,可以取消~T()中对某个函数的调用……


其实我对scopeguard评价很高的……
insert(pair<int,string>(12,"26")); 比较困难,但可以写
insert(make_pair(12,"26"));
find_if(beg, end, binder< ...  —— 不查资料我真忘这里该怎么写了
find_if(beg, end, bind1st(less<int>(), 12) );  虽然依然别扭,但还是可以写出来的
即使利用函数模板对参数的推导,省去书写类型的麻烦。

但这只对临时变量有用,而临时变量的生命周期太短……
当我想实现一个更范化的rollback方式(为每个需求都写一个class与析构太麻烦),真的就盼着auto赶紧被支持……
直到看见scopeguard……  妈的!原来可以这样!!!
----
我感到火大的地方不是scope guard本身。事实上我认为scope guard是了不起的创造,但不得不使用这样的形式,说明用户正在受制于某些可以忍受却实质上扭曲的语言的语义规则之下——尽管大部分人没意识到。
不管怎么说,scope guard没有直观到是一般人学着学着就能自己发明出来的轮子。而它的功能却是非常直观且作用显著的,我故意讲的抽象点,也就是——协助完成程序流程的控制。
作为scope guard,大多数情况下,我并不需要它保存状态,也不需要它可被寻址,那么它为什么就非得是个对象?很简单,在C++中,除了对象,没有其它有效的抽象机制能够完成这个任务。作为用户我无能为力。虽然仅对scope guard来说,用对象来实现没有决定性的不利(额外开销就算傻帽编译器愣着不给你优化也可能小到可以忽略不计),但也已经足够干扰到思维了——至少对于还没习惯这个技巧的人来说。
这种干扰很大一部分来自语义规则之间没有直观意义的耦合。另一方面,表述单一的行为时,需要依赖于很多规则,这些规则限制的程序行为的大部分只是为了让它们能够是well-formed,和表达者的本意无关。这应该是C++被认为复杂(多少是无谓的)的一个重要原因。
想一下,你写下这些例子的时候,为了提出~T() 的调用是编译or运行,用到多少东西?光是引用绑定规则+生存期就够人喝一壶的了。这只是沧海一粟。
……扯远了。
更本质上的,是析构函数的话题。
先回答你的问题:所有的~T()的调用是运行期。但在编译期(乃至之前)我能预料到这种调用出现的范围——在哪些调用之前,哪些调用之后。
很多情况下析构函数并非着重体现它最显著的(和“构造”相对的)意义:释放对象所有的资源,而仅仅是提供“对象生存期结束前发生的事件”的而已。这两者并非直接相关,只是由于C++对象模型的关系而相关。对象模型来源于C,但C的对象本质上只是存储,或者说只是数据,和控制流全然无关;显然进化成C++的现在这个需要做出不少修改。为什么在扩充对象模型的时候顺带附加了这些语义?是懒得去想应该多提供哪些接口么?把这两者复合在一起真的自然么?接口的简单却容易导致理解上的复杂。如果用户没有想到需要去理解对象模型,那么靠什么“学会”这种idiom,死记硬背还是故意去刷经验?
It works, and may be simple enough on writing. But what are the things we should comprehend when we see this portion of program text? Awesome, 1000 readers have their 1000 Hamlet, but nothing helps for programing directly, anyway.

论坛徽章:
1
水瓶座
日期:2014-03-20 18:21:14
126 [报告]
发表于 2011-10-18 19:56 |只看该作者
C的对象本质上是存储
幻の上帝 发表于 2011-10-18 19:52


所有的东西本质上都是存储,比如JVM,也是在内存里面开了一块当作CS,一块当作DS,一块当作寄存器
计算机的一切本质上都是指令+存储,无它

论坛徽章:
0
127 [报告]
发表于 2011-10-18 20:01 |只看该作者
所有的东西本质上都是存储,比如JVM,也是在内存里面开了一块当作CS,一块当作DS,一块当作寄存器
计算 ...
ecloud 发表于 2011-10-18 19:56


表达可计算性的东西也是存储?呵呵。
好吧,就算所有的东西都可以变成存储,那么我不需要的时候为什么无权让它从眼前消失呢?

论坛徽章:
0
128 [报告]
发表于 2011-10-18 20:01 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
1
水瓶座
日期:2014-03-20 18:21:14
129 [报告]
发表于 2011-10-18 20:07 |只看该作者
表达可计算性的东西也是存储?呵呵。
好吧,就算所有的东西都可以变成存储,那么我不需要的时候为什么 ...
幻の上帝 发表于 2011-10-18 20:01



    为什么无权?实模式就可以啊,但是有人嫌“动作太大”啊,这不才有了保护模式么?保护模式“保护”的是什么?不就是不允许你这种“手贱”的人随意让你不喜欢的东西消失么!

论坛徽章:
0
130 [报告]
发表于 2011-10-18 20:10 |只看该作者
为什么无权?实模式就可以啊,但是有人嫌“动作太大”啊,这不才有了保护模式么?保护模式“保护 ...
ecloud 发表于 2011-10-18 20:07


你把“消失”理解错了吧。
我说的“消失”是可以置之不理,不是说去搞破坏。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP