我熟悉C中的嵌套范围规则,其中嵌套块内的相同变量名称会影响具有相同名称的外部变量。 但是对于以下代码片段,我无法确定输出的解释。
var pr1 = db.queryAsync('SELECT * FROM safeplusdb.vector;')
.then(function(records){
for(i=0; i<records.length; i++)
{
if(records[i].type=="ADSL")
{
struct.labelAdsl=records[i].type;
}
else if (records[i].type=="Cable")
{
struct.labelCable=records[i].type;
}
else if (records[i].type=="Fibre")
{
struct.labelFibre=records[i].type;
}
else if (records[i].type=="Others")
{
struct.labelOthers=records[i].type;
}
else if (records[i].type=="Ott")
{
struct.labelOtt=records[i].type;
}
else if (records[i].type=="Satellite")
{
struct.labelSatellite=records[i].type;
}
else if (records[i].type=="Tnt")
{
struct.labelTnt=records[i].type;
}
}
})
.catch(function(err){
throw err;
});
var pr2 = db.queryAsync("SELECT * FROM safeplusdb.data;")
.then(function (records){
for(i=0; i<records.length; i++)
{
let record= records[i];
if(record.vector_id==0)
{
factorizeSQL(UTCGap, struct.cllForecastAdsl, struct.valueReturnAdsl, record);
}
else if(record.vector_id==1)
{
factorizeSQL(UTCGap, struct.cllForecastCable, struct.valueReturnCable, record);
}
else if(record.vector_id==2)
{
factorizeSQL(UTCGap, struct.cllForecastFibre, struct.valueReturnFibre, record);
}
else if(record.vector_id==3)
{
factorizeSQL(UTCGap, struct.cllForecastOthers, struct.valueReturnOthers, record);
}
else if(record.vector_id==4)
{
factorizeSQL(UTCGap, struct.cllForecastOtt, struct.valueReturnOtt, record);
}
else if(record.vector_id==5)
{
factorizeSQL(UTCGap, struct.cllForecastSatellite, struct.valueReturnSatellite, record);
}
else if(record.vector_id==6)
{
factorizeSQL(UTCGap, struct.cllForecastTnt, struct.valueReturnTnt, record);
}
}
})
.catch(function(err){
throw err;
});
var pr3 = db.queryAsync("SELECT * FROM safeplusdb.admin;")
.then(function (records){
for(i=0; i<records.length; i++)
{
struct.adminList[i]=records[i].name;
}
})
.catch(function(err){
throw err;
});
var pr4 = db.queryAsync("SELECT * FROM safeplusdb.media;")
.then(function (records){
for(i=0; i<records.length; i++)
{
struct.mediaList[i] = { label : records[i].label, value : records[i].value};
}
})
.catch(function(err){
throw err;
});
var pr5 = db.queryAsync("SELECT * FROM safeplusdb.scroll ORDER BY orderscroll;")
.then(function (records){
for(i=0; i<records.length; i++)
{
let record= records[i];
if(record.isscrolled==false)
{
if(record.idm==null && record.vector_id !=null)
{
struct.listUnScroll[struct.indj] = {media : null, platform : null, orderscroll: null};
struct.listUnScroll[struct.indj].orderscroll = record.orderscroll;
struct.listUnScroll[struct.indj].platform = struct.listPlatforms[record.vector_id];
struct.indj++;
}
else if(record.vector_id==null && record.idm!=null)
{
struct.listUnScroll[struct.indj] = {media : null, platform : null, orderscroll: null};
struct.listUnScroll[struct.indj].orderscroll = record.orderscroll;
struct.listUnScroll[struct.indj].media = struct.listMedias[record.idm-1];
struct.indj++;
}
else
{
struct.listUnScroll[struct.indj] = {media : null, platform : null, orderscroll: null};
struct.listUnScroll[struct.indj].orderscroll = record.orderscroll;
struct.listUnScroll[struct.indj].media = struct.listMedias[record.idm-1];
struct.listUnScroll[struct.indj].platform = struct.listPlatforms[record.vector_id];
struct.indj++;
}
}
else if(record.isscrolled==true)
{
if(record.idm==null && record.vector_id !=null)
{
struct.listScroll[struct.indk] = {media : null, platform : null, orderscroll: null};
struct.listScroll[struct.indk].orderscroll = record.orderscroll;
struct.listScroll[struct.indk].platform = struct.listPlatforms[record.vector_id];
struct.indk++;
}
else if(record.vector_id==null && record.idm!=null)
{
struct.listScroll[struct.indk] = {media : null, platform : null, orderscroll: null};
struct.listScroll[struct.indk].orderscroll = record.orderscroll;
struct.listScroll[struct.indk].media = struct.listMedias[record.idm-1];
struct.indk++;
}
else
{
struct.listScroll[struct.indk] = {media : null, platform : null, orderscroll: null};
struct.listScroll[struct.indk].orderscroll = record.orderscroll;
struct.listScroll[struct.indk].media = struct.listMedias[record.idm-1];
struct.listScroll[struct.indk].platform = struct.listPlatforms[record.vector_id];
struct.indk++;
}
}
}
})
.catch(function(err){
throw err;
});
var pr6 = db.queryAsync("SELECT * FROM safeplusdb.device;")
.then(function (records){
for(i=0; i<records.length; i++)
{
struct.deviceList[i] = {value : records[i].value, label : records[i].label};
}
})
.catch(function(err){
throw err;
});
var pr7 = db.queryAsync("SELECT * FROM safeplusdb.listmsd;")
.then(function (records){
for(i=0; i<records.length; i++)
{
let aaa = records[i].namelist;
let ccc = [];
struct.msdList[i] = {id: records[i].idlistmsd, labelList: aaa, msds : []};
}
let k = struct.msdList.length;
db.queryAsync("SELECT * FROM safeplusdb.msd;")
.then(function (records1)
{
for(j=0; j<records1.length; j++)
{
for(l=0;l<k;l++)
{
if(records1[j].listmsd==struct.msdList[l].id)
{
struct.msdList[l].msds.push(records1[j].msd);
}
}
}
})
.catch(function(err){
throw err;
});
})
.catch(function(err){
throw err;
});
Promise.all(pr1, pr2, pr3, pr4, pr5, pr6, pr7)
.then(function(){
console.log(struct);
})
.catch(function(err){
throw err;
});
}
上述代码段的输出为:
x = 1,y = 2,z = 3
x = 10,y = 20.000000,z = 3
x = 1,y = 20.000000,z = 2
请有人帮我理解第三个printf语句中#include <stdio.h>
int main()
{
int x = 1, y = 2, z = 3;
printf(" x = %d, y = %d, z = %d \n", x, y, z);
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
return 0;
}
的值如何产生超出范围的变量值。
首先我认为它可能是垃圾值,因为打印y
整数会产生垃圾值,因此将内部范围中%f
的值更改为其他值会产生与输出相同的值因此,我确认这不是垃圾值。
我使用gcc版本6.3.1 20161221(Red Hat 6.3.1-1)(GCC)编译了程序,并使用各种在线编译器编译了程序。
答案 0 :(得分:10)
您有一个未定义的行为:
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z); // here y is an int
}
如果printf()
中的标记与良好类型不匹配,则这是未定义的行为。
您必须使用%d
标志。
{
int z = 100;
printf(" x = %d, y = %d, z = %d \n", x, y, z); // here y is an int
}
答案 1 :(得分:8)
问题在于格式说明符和提供的参数不匹配。让我们仔细看看。
在第一个内部范围
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
y
被(重新)定义为float
,并且使用该变量作为%f
转换说明符的参数非常好。但是,一旦范围结束,( the visble )y
再次为int
。因此,在第二个内部范围
printf(" x = %d, y = %f, z = %d \n", x, y, z);
^^^^^^
使用%f
是错误的并导致undefined behavior。您必须使用%d
打印y
那里的值。
相关,引用C11
,章节§6.2.1/ P4
每个其他标识符的范围由其声明的位置决定(在 声明者或类型说明符)。
[...]
如果是声明符或类型说明符 声明标识符出现在块内或参数声明列表中 一个函数定义,标识符有块作用域,它终止于 相关块。
[....]
如果标识符指定同名的两个不同实体 空间,范围可能重叠。如果是这样,一个实体(内部范围)的范围将结束 严格地在另一个实体的范围之前(外部范围)。在内部范围内, identifier指定在内部作用域中声明的实体;在外部宣布的实体 范围在内部范围内隐藏(并且不可见)。
并且,与UB相关,来自章节§7.21.6.1
[...]如果有任何论据 不是相应转换规范的正确类型,行为是 未定义。
答案 2 :(得分:4)
首先我认为它可能是垃圾值,因为打印带有%f的整数会产生垃圾值,所以将内部范围中的y值更改为其他值会产生与输出相同的值,因此我确认它不是垃圾值。
这是一个错误的假设。它是“垃圾”,因为你在这里有未定义的行为。
我引用自己对未定义行为的解释:
中未定义的行为
C
C是一种非常低级的语言,其结果如下:
没有什么能阻止你做一些完全错误的事情。
许多语言,尤其是某些托管环境的语言,例如
Java
或者C#
当你做不允许的事情时,实际上会阻止你,比方说, 访问不存在的数组元素。C
没有。只要你的 程序语法正确,编译器不会抱怨。如果你这样做 在你的程序中被禁止的东西,C
只是调用你的行为 程序未定义。这正式允许在运行时发生任何事情 该程序。通常,结果将是崩溃或只是输出“垃圾” 值,如上所示。但如果你真的不走运,你的计划似乎就会出现 正常工作直到它得到一些稍微不同的输入,并由此 时间,你将很难找到你的计划的确切位置 未定义。因此,一定要避免未定义的行为!。另外,未定义的行为也会导致安全漏洞。这个 在实践中已经发生了很多。
你遇到程序似乎做了类似正确执行的事情之一,这是运气不好。
但它未定义,并且证明使用未经修改的代码在我的机器上发生了什么:
$ ./scope
x = 1, y = 2, z = 3
x = 10, y = 20.000000, z = 3
x = 1, y = 0.000000, z = 3
旁注:尽管 shadowing 定义明确,但您也应该避免使用它。使用阴影创建错误代码只是冒险,因为虽然编译器没有问题,但你开始混淆你的变量。
答案 3 :(得分:1)
尝试下面的代码中的方式! ;)
问题如其他答案所示。您忘记了y
变量是范围int
!!!
#include <stdio.h>
int main()
{
int x = 1, y = 2, z = 3;
printf(" x = %d, y = %d, z = %d \n", x, y, z);
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, (float)y, z);
}
return 0;
}
答案 4 :(得分:1)
在我的英特尔平台上用VC解释了未定义的行为,因为%f
格式说明符需要在堆栈上加倍,这大于int
所以当它检索该值,它检索的字节数多于int,现在假定堆栈上不同位置的下一个参数,导致z
打印错误(即打印时不是z
)。