我想研究一下如何将某些C/C++特性转换为汇编,并创建了以下文件:
struct foo {
int x;
char y[0];
};
char *bar(struct foo *f)
{
return f->y;
}
Run Code Online (Sandbox Code Playgroud)
然后我编译了这个gcc -S
(并且也试过g++ -S
)但是当我查看汇编代码时,我很失望地发现bar函数中的一个微不足道的冗余,我认为gcc
应该能够优化掉:
_bar:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movabsq $4, %rcx
addq %rcx, %rax
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
popq %rbp
ret
Leh_func_end1:
Run Code Online (Sandbox Code Playgroud)
除其他外,线条
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
Run Code Online (Sandbox Code Playgroud)
似乎毫无意义多余.是否有任何理由gcc(可能还有其他编译器)不能/不优化它?
在大多数现代64位处理器(例如Intel Core 2 Duo或Intel i7系列)上,x86_64命令mulq
及其变体的速度是否取决于操作数?例如,乘法11 * 13
会比11111111 * 13131313
?或者它总是花费最坏情况的时间?
我试图在python中编写一个类似于方案的小语言,以便更好地理解方案.
问题是我被困在语法对象上.我无法实现它们,因为我不太了解它们的用途以及它们的工作原理.
为了尝试理解它们,我在DrRacket中使用了语法对象.
从我能够发现的情况来看,评估#'(+ 2 3)
与评估没有什么不同'(+ 2 3)
,除非在+
顶级命名空间中存在一个词汇变量,在这种情况下(eval '(+ 2 3))
仍会返回5
,但(eval #'(+ 2 3))
只会抛出错误.
例如:
(define (top-sym)
'(+ 2 3))
(define (top-stx)
#'(+ 2 3))
(define (shadow-sym)
(define + *)
'(+ 2 3))
(define (shadow-stx)
(define + *)
#'(+ 2 3))
Run Code Online (Sandbox Code Playgroud)
(eval (top-sym))
,(eval (top-stx))
和(eval (shadow-sym))
所有返回5
,同时(eval (shadow-stx))
抛出错误.他们都没有回来6
.
如果我不知道更好,我会认为语法对象唯一特别的事情(除了他们存储代码位置以获得更好的错误报告的琐碎事实)是他们在某些情况下抛出错误符号对应物将返回可能不需要的值.
如果故事很简单,那么在常规列表和符号上使用语法对象就没有什么好处.
所以我的问题是:我对语法对象缺少什么让它们如此特别?
例如,在以下示例中:
type Food interface {
Eat() bool
}
type vegetable_s struct {
//some data
}
type Vegetable *vegetable_s
type Salt struct {
// some data
}
func (p Vegetable) Eat() bool {
// some code
}
func (p Salt) Eat() bool {
// some code
}
Run Code Online (Sandbox Code Playgroud)
难道Vegetable
和Salt
两个满足Food
,即使一个是一个指针,另一个是直接一个结构?
举个简单的例子:
(define-macro-variable _iota 0) ; define-macro-variable does not really exist
(define-syntax (iota stx)
(syntax-case stx ()
((iota)
(let ((i _iota))
(set! _iota (+ i 1))
#`#,i))))
Run Code Online (Sandbox Code Playgroud)
这样给出:
(define zero (iota))
(define one-two-three (list (iota) (iota) (iota)))
(define (four) (iota))
Run Code Online (Sandbox Code Playgroud)
以下都应评估为#t
:
(equal? zero 0)
(equal? one-two-three '(1 2 3)) ; possibly in a different order
(equal? (four) 4)
(equal? (four) 4)
(equal? (four) 4)
Run Code Online (Sandbox Code Playgroud)
是否有任何真正的球拍功能define-macro-variable
可以完成上述示例中应该执行的操作?
编辑:
我找到了解决办法:
(define-syntaxes (macro-names ...)
(let (macro-vars-and-vals ...)
(values macro-bodies-that-nead-the-macro-vars ...)))
Run Code Online (Sandbox Code Playgroud)
但我更喜欢一种解决方案,它不需要使用宏变量的所有宏都在一个表达式中.
例如foo.h
:
typedef struct foo_t foo_t;
/* Lots of function declarations dealing with foo_t... */
int foo_print(const foo_t *foo); /* Print foo to stdout. */
int foo_fprint(FILE *f, const foo_t *foo); /* Print foo to file f. */
Run Code Online (Sandbox Code Playgroud)
我不想丢弃foo.h
太多其他用户foo.h
可能不想包含的头文件,但我确实需要声明采用类型的函数FILE*
.我怀疑自己是第一个遇到这种困境的人,所以在这种情况下人们通常会做些什么呢?或者我错误地想要避免包含stdio.h
在我的头文件中?
编辑:
人们似乎不理解我的问题.澄清一下,这里有一些潜在的解决方案:
stdio.h
而不用担心它会导致客户端代码发生冲突(例如,如果他们碰巧有自己的函数碰巧被调用getchar
).#ifdef
来查明是否stdio.h
已经包含,然后才声明FILE*
相关函数.这样做的缺点是它会#include
在我的客户代码中强加一个特定的排序.foo_io.h
.什么是最好的事情是什么问题?
我有以下功能:
func fitrange(a, x, b int) int {
if a > b {
a, b = b, a
}
switch true {
case x < a:
return a
case x > b:
return b
default:
return x
}
}
Run Code Online (Sandbox Code Playgroud)
go编译器抱怨"函数在没有return语句的情况下结束",即使语句中的每个可能路径都switch
返回一个值.除了return
在函数末尾添加一个虚拟语句之外,还有什么方法可以解决这个问题吗?
假设我有一个非常大的文件foo.txt
,我希望在找到正则表达式时迭代它.目前我这样做:
f = open('foo.txt')
s = f.read()
f.close()
for m in re.finditer(regex, s):
doSomething()
Run Code Online (Sandbox Code Playgroud)
有没有办法在不必将整个文件存储在内存中的情况下执行此操作?
注意:逐行读取文件不是一个选项,因为正则表达式可能跨越多行.
更新:stdin
如果可能的话,我也希望这样做.
更新:我正在考虑以某种方式使用自定义文件包装器模拟字符串对象,但我不确定正则表达式函数是否会接受自定义的类似字符串的对象.
例如,我可以做这样的事情,以便只能foo.c
修改变量foo
吗?:
foo.h
:
extern const int foo;
void foo_init(void);
void foo_reinit(void);
Run Code Online (Sandbox Code Playgroud)
foo.private.h
:
int foo;
void foo_init(void);
void foo_reinit(void);
Run Code Online (Sandbox Code Playgroud)
foo.c
:
#include "foo.private.h"
void foo_init() { foo = 1; /* ... */ }
void foo_reinit() { foo++; /* ... */ }
Run Code Online (Sandbox Code Playgroud)
bar.c
:
#include <foo.h>
int main()
{
foo_init(); printf("foo: %d\n", foo);
foo_reinit(); printf("foo: %d\n", foo);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
因此,以下将产生错误/警告:
baz.c
:
#include <foo.h>
int main()
{
foo_init(); printf("foo: %d\n", foo);
foo = 0; /* ERROR/WARNING …
Run Code Online (Sandbox Code Playgroud) 举例来说,如果我有两个文件foo.c
和bar.o
,并foo.c
包含一个函数foo()
引用的函数bar()
中bar.o
:
int foo(int x) { x = bar(x); /* ... */ }
Run Code Online (Sandbox Code Playgroud)
如何编译暴露foo()
但不暴露的静态或动态库bar()
?换句话说,我想bar()
只在库内链接.