关键词:
【中文标题】为啥不能打印errno的值?【英文标题】:Why can't errno's value be printed?为什么不能打印errno的值? 【发布时间】:2012-07-14 19:03:00 【问题描述】:我正在查看 SO“低质量”帖子中的以下代码以确保示例有效,我的问题是为什么我不能打印 errno 的值?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main()
FILE *fp;
errno = 0;
fp=fopen("Not_exist.txt","r");
if(fp == NULL && errno == ENOENT)
perror("file not exist");
return 0;
当我尝试打印该值时会发生以下情况:
(gdb) p errno
Cannot find thread-local variables on this target
(gdb)
我可以很好地打印 fp 的值。如您所料,它的值为0x00
。
我查看了/usr/include/errno.h
和许多其他包含在errno.h
中的包含文件,但我无法弄清楚errno 是如何定义的。任何指示或帮助将不胜感激。我只是对此感到好奇;什么都没有。
谢谢。
【问题讨论】:
下次尝试使用ferror(my-file-pointer)
。
你能从你的程序中打印出errno
的值吗? printf("errno = %d\n", errno);
在检查核心转储时是否也可以打印errno
?那时你不能运行任何功能。
【参考方案1】:
errno
变量有点奇怪。因为现在大多数运行时库都支持线程,所以不能只有 一个 errno
变量。如果有,那么两个线程可以同时做一些事情,都设置了errno
值,然后就会产生很大的混乱。
运行时库会使用各种技巧来避免这个问题。例如,可能会执行以下操作:
#define errno __get_errno()
其中对errno
的引用实际上调用了内部__get_errno()
函数,该函数返回当前线程的正确错误编号值。这种方法的缺点是它会阻止分配给 errno,例如 errno = 0;
(某些代码可能会这样做)。运行时库通常会选择更复杂的方法。
一些运行时库(我想就像您正在使用的那个)可以声明一种特殊类型的“线程局部变量”,它可以在每个线程上具有不同的值。听起来您系统上的调试器无法显示这种变量。
【讨论】:
我见过的方法是#define errno *__get_errno()
; __get_errno()
返回一个指针,宏取消引用它。这样,它是可赋值的并且仍然封装在一个函数中。
是的,这是在没有特定编译器支持的情况下进行线程本地存储的一种方式。【参考方案2】:
在我的 Ubuntu 安装中,bits/errno.h
中有以下部分:
/* Function to get address of global `errno' variable. */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value. */
# define errno (*__errno_location ())
# endif
也就是说,errno
不一定是变量。由于各种原因,您可能希望有一个函数为您返回错误值,而不是简单的extern int
。1这就是为什么您不能使用 GDB 打印它的值。
1当然,如您所见,函数调用应该返回指向实际变量的指针,而errno
宏会取消引用它。
【讨论】:
errno
必然是一个左值,所以你可以赋值给它。
@KeithThompson,我没有说它不是左值。我说它不一定是一个变量。 gdb,或者至少是那个特定版本,将能够读取由名称标记的内存位置(例如变量i
),但可能不能(在这种情况下似乎是这样)执行一个函数来返回它的值。
我的意思是errno
不能是(定义为的宏)返回int
值 的函数;你最后一段中的第二句话可能暗示它可以。当然,它可以是一个扩展为一个表达式的宏,该表达式包含对返回 int*
的函数的调用。
@KeithThompson,我添加了一条评论来澄清。【参考方案3】:
正如其他人所说,errno
不是 gdb 可以打印的变量。但是gdb可以
评估函数,__errno_location()
返回一个指向 `errno' 的指针。那么我们唯一需要做的就是调用函数并取消引用结果:
(gdb) p *__errno_location()
就是这样。
【讨论】:
【参考方案4】:errno
实际上是 C 标准要求的扩展为可修改左值的宏。在最简单的情况下,它可以扩展为已声明变量的名称,但对于需要不同线程的不同 errno
对象的实现,它通常定义如下:
#define errno (*__errno_location ())
gdb
通常能够评估函数调用;例如,在我的系统上:
(gdb) p __errno_location()
$1 = -134383968
(gdb) p errno
Cannot find thread-local variables on this target
第一个打印的值恰好是__errno_location()
返回的指针值的低 32 位。我不太了解 gdb 来解释这种行为,但它确实证明了它可以执行函数调用。
作为一种解决方法,您可以修改源代码,以便将errno
的地址或其值保存在 gdb 可以显示的变量中:
(gdb) l
1 #include <errno.h>
2 #include <stdio.h>
3 int main(void)
4 errno = 42; /* arbitrary value */
5 const int *errno_ptr = &errno;
6 int errno_value = errno;
7 printf("%d %d %d\n", errno, errno_value, *errno_ptr);
8
(gdb) b 8
Breakpoint 1 at 0x4005b6: file c.c, line 8.
(gdb) r
Starting program: /home/kst/c
42 42 42
Breakpoint 1, main () at c.c:8
8
(gdb) p errno
Cannot find thread-local variables on this target
(gdb) p errno_value
$1 = 42
(gdb) p *errno_ptr
$2 = 42
*errno_ptr
方法的优点是您只需分配一次 -- 除非您正在调试多线程程序。在这种情况下,&errno
的值可能会因您评估它的线程而异。
这可能是gdb
中的一个错误,或者至少是一个缺失的功能。
更新 Kevin Cox 的评论提出了一种解决方法:
print *((int*(*)())__errno_location)()
对于 gcc 6.2 和 gdb 7.11,print errno
确实有效:
(gdb) l
1 #include <errno.h>
2 int main(void)
3 errno = 42;
4 return 0;
5
(gdb) b 4
Breakpoint 1 at 0x6bf: file c.c, line 4.
(gdb) r
Starting program: /home/kst/c
Breakpoint 1, main () at c.c:4
4 return 0;
(gdb) p errno
$1 = 42
(gdb)
【讨论】:
它被截断的原因是因为没有提供函数签名的调试信息,所以 gdb 假定它是 int()() 当它实际返回一个 int 时。要解决此问题,您可以将符号转换为正确的函数类型,然后再调用它print *((int*(*)())__errno_location)()
请注意,如果您使用调试符号进行编译,打印errno
将始终有效,问题是如果您没有调试符号,编译器不知道 errno 是什么(因为它是一个宏)。
@KevinCox:嗯。我假设如果你要使用gdb
,无论如何你都需要使用调试符号(gcc -g ...
)进行编译。
您不需要这样做,有时您会陷入符号不可用的不幸情况。相信我,当没有可用的符号时能够读取 errno 是 huuuuge 的好处。【参考方案5】:
_CRTIMP int* __cdecl __MINGW_NOTHROW _errno(void);
#define errno (*_errno())
这样,您可以只传递首选验证的地址,该地址将包含从调用函数返回的实际错误值。
例如您可以定义函数 _errno() 如下
unsigned int errorValue;
int* _errno()
return (&errorValue);
现在用法:
void MyFunc()
if(some condition failure)
errno = 10; //Or any error value as per your design
else
//Actual operation
MyFunc()
执行后,errorValue
将包含错误。
【讨论】:
这如何回答这个问题?为啥版本不能打印?
】为啥版本不能打印?【英文标题】:Whyversionisnotprintable?为什么版本不能打印?【发布时间】:2017-11-2400:44:19【问题描述】:我有这个班轮:perl-Mversion-e\'our$VERSION=v1.02;print$VERSION\'输出是(不可见,有两个字符:1、2):为什么... 查看详情
为啥我打印的值超出范围?
】为啥我打印的值超出范围?【英文标题】:WhyI\'mprintingvalueoutofrange?为什么我打印的值超出范围?【发布时间】:2016-04-0417:13:20【问题描述】:考虑这段代码:classFoo123QList<int>a=(QList<int>())<<1<<2<<3;QList<int... 查看详情
为啥 Instant 在彼此之后打印时显示不同的值? [关闭]
】为啥Instant在彼此之后打印时显示不同的值?[关闭]【英文标题】:WhydoesInstantdisplaydifferentvalueswhenprintedaftereachother?[closed]为什么Instant在彼此之后打印时显示不同的值?[关闭]【发布时间】:2018-06-1915:22:09【问题描述】:为什么... 查看详情
解释为啥类不存储和打印输入的值
】解释为啥类不存储和打印输入的值【英文标题】:Explainingwhyclassesarenotstoringandprintingoutenteredvalue解释为什么类不存储和打印输入的值【发布时间】:2015-12-0623:27:49【问题描述】:我是类新手,我必须在一个类中编写自己的函数... 查看详情
为啥我不能像这样覆盖变量的值?
】为啥我不能像这样覆盖变量的值?【英文标题】:Whycan\'tIoverwritethevalueofavariablelikethis?为什么我不能像这样覆盖变量的值?【发布时间】:2015-09-0920:27:53【问题描述】:我试图弄清楚为什么我无法覆盖通过隔离范围(@)传递给angu... 查看详情
为啥代码不能打印这个二维数组的元素?
】为啥代码不能打印这个二维数组的元素?【英文标题】:Whycantthecodeprinttheelementsofthis2darray?为什么代码不能打印这个二维数组的元素?【发布时间】:2018-02-0613:49:00【问题描述】:好的,所以我编写了这段代码来打印二维数组... 查看详情
为啥在 Pytorch 中打印 GPU 张量的值需要这么长时间?
】为啥在Pytorch中打印GPU张量的值需要这么长时间?【英文标题】:WhydoesittakesolongprintthevalueofaGPUtensorinPytorch?为什么在Pytorch中打印GPU张量的值需要这么长时间?【发布时间】:2021-06-0305:43:20【问题描述】:我编写了这个pytorch程序... 查看详情
为啥我不能更改 Timer.scheduledTimer 函数中变量的值?
】为啥我不能更改Timer.scheduledTimer函数中变量的值?【英文标题】:WhyIcannotchangethevalueofvariableinsideTimer.scheduledTimerfunction?为什么我不能更改Timer.scheduledTimer函数中变量的值?【发布时间】:2020-05-2220:05:36【问题描述】:当我尝试... 查看详情
为啥我不能在我的结构中打印名称?
】为啥我不能在我的结构中打印名称?【英文标题】:HowcomeIcan\'tprintthenameinmystructure?为什么我不能在我的结构中打印名称?【发布时间】:2019-03-1422:51:20【问题描述】:我正在读取具有名称ID和等级的数据文件,并将信息存储在... 查看详情
为啥数组的值是undefined
为什么itemArr是undefined,console.log("data======="+JSON.stringify(data))打印出来是有值的,求教大神参考技术A首先定义一个数组vararr=[2,4,5,3,5,3,0];//这里以整形数组为例确定数组的长度arr.length;利用循环语句遍历数组vararr=[2,4,5,3,5,3,0]... 查看详情
为啥 const char* 返回值丢失了两个字符?但是在返回之前打印正确的值[重复]
】为啥constchar*返回值丢失了两个字符?但是在返回之前打印正确的值[重复]【英文标题】:Whyisconstchar*returningvaluewithtwocharacterslost?Howeverprintstherightvaluejustbeforereturning[duplicate]为什么constchar*返回值丢失了两个字符?但是在返回之前... 查看详情
为啥不能将“UIView”类型的值转换为其他视图?
】为啥不能将“UIView”类型的值转换为其他视图?【英文标题】:Whycouldnotcastvalueoftype\'UIView\'tootherView?为什么不能将“UIView”类型的值转换为其他视图?【发布时间】:2018-10-2112:35:12【问题描述】:这个问题与我之前的问题处理... 查看详情
为啥不能比较两个 int 类型变量的值? [复制]
】为啥不能比较两个int类型变量的值?[复制]【英文标题】:Whycan\'tyoucomparethevalueoftwointtypevairables?[duplicate]为什么不能比较两个int类型变量的值?[复制]【发布时间】:2018-12-3018:43:21【问题描述】:我在学习c++时只是在编译一些... 查看详情
为啥props里面的值不能监听到
参考技术AReact的props吗?props不是处于观察状态的,自然是监听不到的,不过你可以在componentWillReceiveProps中可以监听到props的变化的。 查看详情
为啥我不能将指令更改为以前的值(函数调用)OllyDbg
】为啥我不能将指令更改为以前的值(函数调用)OllyDbg【英文标题】:WhyIcan\'tchangeinstructiontoit\'spreviousvalues(functioncall)OllyDbg为什么我不能将指令更改为以前的值(函数调用)OllyDbg【发布时间】:2020-09-1023:48:01【问题描述】:我... 查看详情
为啥下面的代码不能得到 n fold = 1 的值?
】为啥下面的代码不能得到nfold=1的值?【英文标题】:Whydoesthefollowingcodecantgetvalueofn_fold=1?为什么下面的代码不能得到nfold=1的值?【发布时间】:2018-03-2201:21:39【问题描述】:使用以下代码时,n_folds必须为2或更多。如何更改它... 查看详情
为啥我们不能在 C 中使用变量作为 e 的值
】为啥我们不能在C中使用变量作为e的值【英文标题】:WhycanwenotuseavariableasvalueofeinC为什么我们不能在C中使用变量作为e的值【发布时间】:2014-04-2208:43:21【问题描述】:我的编译器不断给我错误,我需要为此使用数字:xek其中k... 查看详情
如果行和列的差大于 1,为啥我不能打印二维数组?
】如果行和列的差大于1,为啥我不能打印二维数组?【英文标题】:Whycan\'tIprinta2darrayiftherowsandcolumnshaveadifferencegreaterthan1?如果行和列的差大于1,为什么我不能打印二维数组?【发布时间】:2021-09-1007:40:47【问题描述】:我创建... 查看详情