我想使用命令行编译器从 MAC OSX 上的命令行编译和链接应用程序。我有一个名为“hello.m”的源文件,如下所示:
#import <Foundation/Foundation.h>
int main(int argc,char *argv[])
{
NSLog(@"hello world\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在命令提示符下,我键入:
$ clang -o hello hello.m
Run Code Online (Sandbox Code Playgroud)
但编译器返回:
Undefined symbols for architecture x86_64:
"_NSLog", referenced from:
_main in main-74f615.o
ld: symbol(s) not found for architecture x86_64
Run Code Online (Sandbox Code Playgroud)
显然,当我调用 NSLog 时,我需要链接到一个库。我需要链接哪个库?
我正在编写一些将由C++代码包含的头文件,也包含在C代码中.我更希望标头源代码保持一致,并始终在这些标头中使用"nullptr"而不是NULL(或整数常量0).
这带来了添加一段代码的可能性,例如:
#ifndef __cplusplus
#define nullptr 0 /* or ((void *)0) */
#endif
Run Code Online (Sandbox Code Playgroud)
或者:
#include <stdio.h>
#ifndef __cplusplus
#define nullptr NULL
#endif
Run Code Online (Sandbox Code Playgroud)
编辑:或者来自Ben Voigt的建议:
#ifndef __cplusplus
static const void *nullptr = 0;
#endif
Run Code Online (Sandbox Code Playgroud)
问题是,这样做的缺点是什么?有什么理由为什么将nullptr添加到C++而不是C?当C++和C必须互操作时,这似乎会使代码更加一致和可读.
编辑:示例标题
#ifdef __cplusplus
extern "C" {
#endif
extern struct MyStruct *globalMyStruct;
extern int myFunc(struct MyStruct *ptr,int arg);
#ifdef __cplusplus
}
#endif
#define MYMACRO(x) ((globalMyStruct!=nullptr) ? myFunc(globalMyStruct,(x)) : -1)
Run Code Online (Sandbox Code Playgroud)
即使MyStruct是C++对象,C代码包含上述头文件并使用MYMACRO定义也是合法的.我想在C和C++文件中包含上面的标题代码.但是如果我从C文件中包含上面的头文件,那么由于使用了nullptr,它将无法编译.
C代码包含指向C++对象的指针是完全有效的,这些指针可以作为参数传递给函数(也许这些函数是用C++编写的).这只是C++和C可以互操作的一种方式.
以下(公认的做作)C程序无法编译:
int main() {
const int array[] = {1,2,3};
static int x = array[1];
}
Run Code Online (Sandbox Code Playgroud)
使用gcc(或Microsoft的CL.EXE)编译上述C源文件时,出现以下错误:
error: initializer element is not constant
static int x = array[1];
^
Run Code Online (Sandbox Code Playgroud)
这种简单直观的语法肯定是有用的,所以这似乎应该是合法的,但显然它不是.当然,我不是唯一一个对这种明显愚蠢的限制感到沮丧的人.我不明白为什么这是不允许的 - 通过使这个有用的语法非法,C语言试图避免什么问题?
看起来它可能与编译器为初始化生成汇编代码的方式有关,因为如果删除"static"关键字(使得变量"x"在堆栈上),那么它编译得很好.
然而,另一个奇怪的事情是它在C++中编译得很好(即使使用static关键字),但在C中却没有.因此,C++编译器似乎能够生成必要的汇编代码来执行这样的初始化.
编辑:相信戴维斯 - 为了安抚SO权力 - 我会寻求以下类型的事实信息来回答这个问题:
是否有支持这些语义的遗留代码会破坏?
这些语义是否已经正式提交给标准委员会?
有没有人有理由拒绝这些语义的允许?
函数 g_dbus_connection_signal_subscribe 非常适合告诉我新的 DBus 对象何时出现(或消失)并带有 InterfacesAdded 信号(或 InterfacesRemoved 信号)。但我需要了解预先存在的对象/接口。
我编写了以下 C 代码片段,以便在从总线添加/删除 DBus 对象时提供回调。为了简单起见,省略了错误检查。
#include <stdio.h>
#include <stdlib.h>
#include <gio/gio.h>
static void signal_cb(GDBusConnection *connection,
const gchar *sender_name,const gchar *object_path,
const gchar *interface_name,const gchar *signal_name,
GVariant *parameters,gpointer user_data)
{
printf("%s: %s.%s %s\n",object_path,interface_name,signal_name,
g_variant_print(parameters,TRUE));
}
int main(int argc,char *argv[])
{
GDBusConnection *c;
GMainLoop *loop;
int filter_id;
c = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,&err);
loop = g_main_loop_new(NULL,0);
filter_id = g_dbus_connection_signal_subscribe(c,
"org.bluez",NULL,NULL,NULL,NULL,
G_DBUS_SIGNAL_FLAGS_NONE,signal_cb,NULL,NULL);
g_main_loop_run (loop);
g_main_loop_unref (loop);
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
所以我想做的是跟踪树的 org.bluez 分支下存在的所有 DBus 对象。(这些代表可插拔蓝牙控制器和每个控制器发现的设备)。我需要了解程序启动之前已经存在的 DBus 对象,并且需要了解程序启动后出现的新对象。
上面的代码告诉我有关新对象的信息,但没有告诉我有关已存在对象的信息。gdbus API …