首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的C代码片段不能工作?简单化的版本确实如此。在没有VA_ARGS的情况下为无符号长时间传递args

为什么我的C代码片段不能工作?简单化的版本确实如此。在没有VA_ARGS的情况下为无符号长时间传递args
EN

Stack Overflow用户
提问于 2010-12-28 22:38:44
回答 3查看 196关注 0票数 0

基本上,我正在为一个专用系统编写printf函数,所以我想在不使用VA_ARGS宏的情况下传递一个可选参数数。我编写了一个简单的示例,这段代码可以工作:

代码语言:javascript
复制
#include <stdio.h>

void func(int i, ...);
int main(int argc, char *argv);

int main(int argc, char *argv) {

    unsigned long long f = 6799000015ULL;
    unsigned long long *g;

    //g points to f
    g = &f;

    printf("natural: %llu in hex: %llX address: %x\n", *g, *g, g);

    //put pointer onto stack
    func(6, g, g);

    return 0;
}

void func(int i, ...) {

    unsigned long long *f;

    //pop value off
    f = *(&i + 1);

    printf("address: %x natural: %llu in hex: %llX\n", f, *f, *f);

}

然而,更大的例子是,我试图把这个转移到不起作用的地方。

(主要职能):

代码语言:javascript
复制
unsigned long long f = 6799000015ULL;
unsigned long long *g;

g = &f;

kprintf("ull test: 1=%U 2=%X 3=%x 4= 5=\n", g, g, g);

(我的不可靠的打印函数,我有麻烦了。也许值得指出的是,这段代码确实适用于由值而不是指针传递的It、char字符串或任何其他%标志。真正有效的和没有符号的长长的唯一区别是一个更大,所以我用值来代替,以确保我不会错误地增加&format+ args部分。这说得通吗?)

代码语言:javascript
复制
void kprintf(char *format, ...)
{
 char buffer[KPRINTF_BUFFER_SIZE];

 int bpos = 0; /* position to write to in buffer */
 int fpos = 0; /* position of char to print in format string */
 char ch; /* current character being processed*/

 /*
  * We have a variable number of paramters so we
  * have to increment from the position of the format
  * argument.
 */
 int arg_offset = 1;

 /*
  * Think this through Phill. &format = address of format on stack.
  * &(format + 1) = address of argument after format on stack.
  * void *p = &(format + arg_offset);
  * kprintf("xxx %i %s", 32, "hello");
  * memory would look like = [ 3, 32, 5, "xxx", 32, "hello" ]
  * get to 32 via p = &(format + 1); (int)p (because the int is copied, not a pointer)
  * get to hello via p = &(format + 2); (char*)p;
  */

 void *arg;
 unsigned long long *llu;
 arg = (void*) (&format + arg_offset);
 llu = (unsigned long long*) *(&format + arg_offset);

 while (1)
 {
  ch = format[fpos++];

  if (ch == '\0')
   break;

  if (ch != '%')
   buffer[bpos++] = ch;
  else
  {
   ch = format[fpos++];
   if (ch == 's')
    bpos += strcpy(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, (char*)arg);
   else if (ch == '%')
    buffer[bpos++] = '%';
   else if (ch == 'i')
    bpos += int_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
   else if (ch == 'x')
    bpos += int_to_hex_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
   else if (ch == 'o')
    bpos += int_to_oct_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
   else if (ch == 'X') {
    //arg is expected to be a pointer we need to further dereference.
    bpos += unsigned_long_long_to_hex(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
   } else if (ch == 'U') {
    bpos += unsigned_long_long_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
   } else
   {
    puts("invalid char ");
    putch(ch);
    puts(" passed to kprintf\n");
   }

   arg_offset++;
   arg = (void *)(&format + arg_offset);
   llu = (unsigned long long*) *(&format + arg_offset);
  }
 }

 buffer[bpos] = '\0';
 puts(buffer);
}

(以及未签名的长函数,它接着称之为):

代码语言:javascript
复制
int unsigned_long_long_to_hex(char *buffer, int max_size, unsigned long long number)
{
 return ull_number_to_str(buffer, max_size, number, BASE_HEX);
}

int unsigned_long_long_to_str(char *buffer, int max_size, unsigned long long number) {
 return ull_number_to_str(buffer, max_size, number, BASE_DECIMAL);
}

int ull_number_to_str(char *buffer, int max_size, unsigned long long number, int base) {

 int bufpos = 0;

 unsigned int lo_byte = (unsigned int) number;
 unsigned int hi_byte = (unsigned int) (number >> 32);

 bufpos = number_to_str(buffer, max_size, lo_byte, base);
 bufpos += number_to_str(buffer + bufpos, max_size, hi_byte, base);

 return bufpos;

}

#define NUMERIC_BUFF_SIZE (11 * (ADDRESS_SIZE / 32))

int number_to_str(char *buffer, int max_size, int number, int base)
{
 char *char_map = "0123456789ABCDEF";

 int remain = 0;
 char buff_stack[NUMERIC_BUFF_SIZE];
 int stk_pnt = 0;
 int bpos = 0;

 /* with this method of parsing, the digits come out backwards */
 do 
 {
  if (stk_pnt > NUMERIC_BUFF_SIZE)
  {
   puts("Number has too many digits to be printed. Increasse NUMBERIC_BUFF_SIZE\n");
   return 0;
  }

  remain = number % base;
  number = number / base;
  buff_stack[stk_pnt++] = char_map[remain];
 } while (number > 0);

 /* before writing...ensure we have enough room */
 if (stk_pnt > max_size)
 {
  //error. do something?
  puts("number_to_str passed number with too many digits to go into buffer\n");
  //printf("error. stk_pnt > max_size (%d > %d)\n", stk_pnt, max_size);
  return 0;
 }

 /* reorder */
 while (stk_pnt > 0)
  buffer[bpos++] = buff_stack[--stk_pnt];

 return bpos;
}

对不起,伙计们,我看不出我做错了什么。我理解这是一个“代码墙”类型的场景,但希望有人能看到我做错了什么。我很感激您可能不喜欢不使用VA_ARGS,但是我不明白为什么这种技术不应该只起作用?而且,我也在与-nostdlib链接。如果有人能帮忙我会很感激的。而且,这并不意味着是生产质量代码,所以如果我缺少一些C基本面,可以自由地对它保持建设性:-)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-12-29 00:55:33

用这种方式编码是个坏主意。使用stdarg.h

为了避免使用标准库,您正在从事业余内核或嵌入式项目(我猜想这是基于名称kprintf),因此我建议您至少编写自己的(体系结构和编译器特定的) stdarg宏集,这些宏符合众所周知的接口和针对这些宏的代码。这样,通过取消对上一个参数的地址的引用,您的代码就不像这样的WTF了。

您可以创建一个存储最后已知地址的va_list类型,您的va_arg宏可以适当地对齐所传递的类型的sizeof,并相应地提前指针。对于我为x86工作过的大多数约定,每种类型都提升到32位.

票数 3
EN

Stack Overflow用户

发布于 2010-12-28 22:43:26

您必须在平台的呼叫约定上读取,即如何传递目标处理器/OS函数参数,以及如何保存寄存器。并非所有参数都在堆栈上传递。根据参数的数量及其类型,可能会出现许多复杂的情况。

票数 2
EN

Stack Overflow用户

发布于 2010-12-28 23:02:47

我要补充的是:如果您想像上面那样手工操作堆栈,您需要使用汇编程序,而不是C语言。C语言遵循定义的标准,而高于它的操作不是法律代码(也就是说,它的含义没有很好地定义)。因此,编译器可以使用它做它想做的任何事情,比如以不适合您的需要的奇怪方式优化它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4550100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档