是否可以声明一些func_t返回该类型的函数类型,func_t?
换句话说,函数是否可以返回自身?
// func_t is declared as some sort of function pointer
func_t foo(void *arg)
{
return &foo;
}
Run Code Online (Sandbox Code Playgroud)
或者我必须使用void *和类型转换?
我正在尝试对二进制文件进行逆向工程,以下指令让我感到困惑,有人可以澄清这究竟是什么吗?
=>0x804854e: repnz scas al,BYTE PTR es:[edi]
0x8048550: not ecx
Run Code Online (Sandbox Code Playgroud)
哪里:
EAX: 0x0
ECX: 0xffffffff
EDI: 0xbffff3dc ("aaaaaa\n")
ZF: 1
Run Code Online (Sandbox Code Playgroud)
我看到它在某种程度上以每次迭代递减1次ECX,并且EDI沿着字符串的长度递增.我知道它会计算字符串的长度,但至于它是如何发生的,以及为什么"al"涉及到我不太确定.
linux内核(和其他地方)中常用的宏container_of是(基本上)定义如下:
#define container_of(ptr, type, member) (((type) *)((char *)(ptr) - offsetof((type), (member))))
Run Code Online (Sandbox Code Playgroud)
在给定指向其中一个成员的指针的情况下,它基本上允许恢复"父"结构:
struct foo {
char ch;
int bar;
};
...
struct foo f = ...
int *ptr = &f.bar; // 'ptr' points to the 'bar' member of 'struct foo' inside 'f'
struct foo *g = container_of(ptr, struct foo, bar);
// now, 'g' should point to 'f', i.e. 'g == &f'
Run Code Online (Sandbox Code Playgroud)
但是,并不完全清楚其中包含的减法是否container_of被视为未定义的行为.
一方面,因为barinside struct foo只是一个整数,所以只*ptr应该是有效的(以及ptr + 1).因此,container_of有效地产生一个表达式 …
在实现我自己的C11编译器时,我试图弄清楚如何处理_Pragma关键字/运算符.C11§6.10.9描述_Pragma为运算符,因此似乎可以用宏重新定义它,即#define _Pragma(x) SOME_OTHER_MACRO(x).此外,该声明#undef _Pragma应该没有影响(假设之前没有#define的_Pragma).这类似于关键字#defined的方式,例如旧的VC++ hack #define for if (0) ; else for.但是,因为_Pragma在转换阶段3期间评估运算符,与执行预处理器指令的阶段相同,所以不清楚这是否是异常; 该标准未提及其未定义的行为是否_Pragma用作宏名称.
我使用以下代码对GCC进行了一些测试:
#define PRAGMA _Pragma
PRAGMA("message \"hi\"")
_Pragma ("message \"sup\"")
#undef PRAGMA
#undef _Pragma
//#define _Pragma(x)
_Pragma("message \"hello\"")
Run Code Online (Sandbox Code Playgroud)
使用gcc -std=c11 -pedantic -Wall -Wextra -c输出进行编译:
tmp.c:2:1: note: #pragma message: hi
PRAGMA("message \"hi\"")
^
tmp.c:4:1: note: #pragma message: sup
_Pragma ("message \"sup\"")
^
tmp.c:8:8: warning: undefining "_Pragma" [enabled by …Run Code Online (Sandbox Code Playgroud) 考虑以下(C11)代码:
void *ptr = aligned_alloc(4096, 4096);
... // do something with 'ptr'
ptr = realloc(ptr, 6000);
Run Code Online (Sandbox Code Playgroud)
由于ptr指向的内存具有4096字节的对齐aligned_alloc,是否(读取:是否保证)在(成功)调用之后保持该对齐realloc?或者内存可以恢复为默认对齐?
在我编写单元测试时,我偶然发现了一些奇怪的行为glibc,关于"%p"和NULL指针.
如果我有一条这样的线printf("NULL pointer is %p\n", NULL);,那么我看到NULL pointer is (nil)印在屏幕上,正如我所料.
如果我改为使用宽字符版本:wprintf(L"NULL pointer is %p\n", NULL);,则打印出来NULL pointer is (,并在左括号处停止.如果我打印非NULL指针,它会打印该指针,包括普通和宽字符版本.这是一个已知的错误glibc,或者我只是遗漏了什么?
注意:我意识到C标准说指针以%p实现定义的方式转换; 只是打印(一个NULL指针似乎不寻常.
我有这样的dat文件
AAAA 1861 9 7 0.00 -1.50 -19.50 9999.00 9999.00 9999.00 9999.00 18.20 9999.00 6.70 135.00 8.00 9999.00 9999.00 9999.00 9999 0 193 250180280600000000
BBBBBBBBB 1861 9 7 0.00 -7.50 36.50 9999.00 9999.00 21.40 1018.10 22.60 9999.00 1.00 68.00 2.00 9999.00 9999.00 9999.00 9999 0 193 451720280600000000
VVVVVVVVV 1861 9 7 0.00 -58.50 10.50 9999.00 9999.00 27.50 9999.00 26.90 9999.00 15.40 45.00 6.00 9999.00 9999.00 9999.00 9999 0 193 357610280600000000
SSSSSSSS 1861 9 7 0.00 117.50 13.50 9999.00 9999.00 28.00 …Run Code Online (Sandbox Code Playgroud) 基本问题:是否可以避免必须显式调用每个虚拟基类的(非默认)构造函数?
背景:我正在开发围绕Windows COM对象的一些类型安全的C++包装器类.我目前的方法是有一个CBaseCOMWrapper类封装一个IUnknown对象进行引用计数.然后,我有一个CCOMWrapper模板类所继承CBaseCOMWrapper,它定义一个包装为特定COM类型(即IDXGIObject,ID3D11Device等).最后,单独的类从这些包装模板继承来提供实际的/额外的功能(即CDXGIObject,CD3D11Device).
例如,我有以下类(成员省略):
class CBaseCOMWrapper { };
template<typename T> // here, T should inherit from IUnknown
class CCOMWrapper : public virtual CBaseCOMWrapper { };
class CDXGIObject : public virtual CCOMWrapper<IDXGIObject> { };
template<>
class CCOMWrapper<IDXGIAdapter> : public virtual CCOMWrapper<IDXGIObject> { };
class CDXGIAdapter : public virtual CCOMWrapper<IDXGIAdapter> { };
Run Code Online (Sandbox Code Playgroud)
这是类型层次结构的对应图:

左列是实际对象,中间列是瘦COM包装器,右列是实际COM对象.实线箭头表示继承,虚线箭头表示封装.
我使用模板特化CCOMWrapper来在中间提供父子关系.
问题:包装器类假定一个指向COM对象的非NULL(也就是有效)指针,所以我不能有一个默认的构造函数.因为层次结构充满了"钻石",所以大部分遗传都是虚拟的; 这意味着每个类的构造函数都必须调用构造函数.因此,在上面的例子中,构造函数CDXGIAdapter必须调用构造函数CCOMWrapper<IDXGIAdapter>, …
我正在研究一个linux驱动程序,我收到了这条警告消息:
/home/andrewm/pivot3_scsif/pivot3_scsif.c:1090: warning: ignoring return value of ‘copy_from_user’, declared with attribute warn_unused_result
Run Code Online (Sandbox Code Playgroud)
违规行是:
if (copy_from_user(tmp, buf, count) < 0)
Run Code Online (Sandbox Code Playgroud)
在检查声明之后copy_from_user,我发现它返回一个unsigned long,所以显然比较总是会失败,所以返回值不会影响比较.那部分是有道理的,但为什么gcc也没有警告它是签名/未签名的比较?这仅仅是编译器的特点吗?或者它是否避免同一表达式两次警告?
包含该行的函数是:
int proc_write(struct file *f, const char __user *buf, unsigned long count, void *data)
{
char tmp[64];
long value;
struct proc_entry *entry;
if (count >= 64)
count = 64;
if (copy_from_user(tmp, buf, count) < 0)
{
printk(KERN_WARNING "pivot3_scsif: failed to read from user buffer %p\n", buf);
return (int)count;
}
tmp[count - 1] = '\0';
if …Run Code Online (Sandbox Code Playgroud) 我为amd64编写了这个小程序集文件.代码的作用对于这个问题并不重要.
.globl fib
fib: mov %edi,%ecx
xor %eax,%eax
jrcxz 1f
lea 1(%rax),%ebx
0: add %rbx,%rax
xchg %rax,%rbx
loop 0b
1: ret
Run Code Online (Sandbox Code Playgroud)
然后我继续组装,然后在Solaris和Linux上反汇编.
$ as -o y.o -xarch=amd64 -V y.s
as: Sun Compiler Common 12.1 SunOS_i386 Patch 141858-04 2009/12/08
$ dis y.o
disassembly for y.o
section .text
0x0: 8b cf movl %edi,%ecx
0x2: 33 c0 xorl %eax,%eax
0x4: e3 0a jcxz +0xa <0x10>
0x6: 8d 58 01 leal 0x1(%rax),%ebx
0x9: 48 03 c3 addq %rbx,%rax
0xc: 48 93 xchgq %rbx,%rax …Run Code Online (Sandbox Code Playgroud)